Solving a Sticky Issue with a Sticky Element
We recently added a new visual element to our subscription settings view in which a semi-transparent overlay covers the view when a user clicks on a button to either reactivate a subscription or an upgrade option. This prevents the user from taking a different action in the view while the reactivation is processing.
Aside from covering the content area, the text and spinning gif must stay fixed on the screen and centered within the overlay edges during scrolling. This posed a challenge given that a fixed element’s position is relative to the viewport. By using position and transform we found a near-perfect yet solid solution given the requirements.
The Basics
A fixed-position element stays in one place even when the page is scrolled. It’s often used for persistent navigations, footers, and anything else the website wants to keep visible as you scroll the page. The below shows an example.
If you place a fixed element within a non-fixed element and don’t specify left, right, top, or bottom values on the fixed element, the top-left corner of the fixed element will be positioned where the top-left corner of the parent is. See the pen below for a demo. We can use this behavior for our new overlay.
How It’s Done
An absolute-positioned div with a semi-transparent background color creates the overlay. Absolute positioning and z-indexing allow the div to cover the content below it. A child div containing the text and background gif was inserted into the overlay. If we assign fixed positioning to the child div, the text does stay fixed when the user scrolls the page. However, it is not vertically and horizontally centered within the bounds of the overlay.
If we apply top: 50% to the child div, it appears vertically centered within the overlay, but technically it’s not. The top value calculates to 50% of the viewport height rather than 50% of the parent div’s computed height. We don’t want the computed value to be based on the parent div anyway because it can overflow the viewport, causing the text and spinner to be below the fold. In our scenario we will still use top: 50% because the overlay covers most of the vertical space of the page. Plus the height of the top blue navigation bar is short enough to maintain a reasonable appearance to the naked eye of vertically centered text.
If we apply any left or right value to the fixed element, the text will not be horizontally centered because the computed value would be based on the viewport’s width. We can wrap the fixed element in another div and apply styles to the new div to affect the positioning of the fixed child. We can improve the fixed element’s position by applying position: absolute and left: 50% to it.
To fine tune the fixed element’s horizontal position, we apply transform: translate(-50%,-50%) to it. The first percentage value shifts the div to the left. The computed value is 50% of the div’s width. The second -50% value shifts the div up by a value 50% of its height. The horizontal shift centers the div as desired. In this scenario shifting the div vertically isn’t critical; its height is small enough to not drastically affect the vertical position to the naked eye. However, if the text is long enough to make a difference, shifting it up improves the position. Plus, if the text were edited, its position would adjust equally along the vertical axis from its center.
One note regarding horizontal alignment of the fixed element: you could apply text-align: center to the div immediately wrapping the fixed element (while also changing the fixed div to a span). This will center it; however, this does not work in Internet Explorer.
Considerations
If your page uses pixel-defined widths rather than percentages, you need to be aware of one gotcha: if you resize your browser so that the viewport is narrower than your page width, the fixed element will remain in its position when you scroll horizontally. This is a known side effect of fixed positioning.
According to CanIUse.com the latest versions of major browsers support the 2D transform property. Some older versions require vendor prefixes. Please visit the site’s 2D transform page for full details.
To improve page performance, consider using the 3D transform property, but be aware that IE9 only supports 2D transform.
Conclusion
By taking advantage of the position and transform properties, we were able to fix-position an element while largely restricting its position to a specific area of the view. Though the solution does not perfectly address the vertical reference of the fixed element, it still works well given the feature requirements.