Recently I encountered a unique layout requirement: keeping an element always fixed on the top while the page contains full screen elements. This is quite tricky to implement, so I will document my solution in case of any inaccurate needs. Especially in the logical positioning processing on small screens, it increases the difficulty.
The effect is difficult to describe in text, so I recorded a screen video to illustrate what I mean. Pay special attention to the main call to action section, that is, the section with the title "Experience Domino now".
Our goal is to display the main call to action on the right in a larger window, and other parts pass under it as the user scrolls down. In a smaller window, the call to action element must be displayed after the main hero area with the title "Start Trial".
There are two main challenges here:
- Create full-screen elements that do not conflict with sticky elements
- Avoid duplicate HTML code
Before we dive into several possible solutions (and their limitations), let's build a semantic HTML structure.
HTML structure
When building such layouts, you may tend to create duplicate call-to-action sections: one for desktop versions, the other for mobile versions, and then toggle their visibility when appropriate. This avoids the hassle of finding the perfect location in HTML and applying CSS that handles both layout requirements. I must admit that I do the same sometimes. But this time, I want to avoid duplicating my HTML code.
Another thing to consider is that we use sticky positioning for .box--sticky
element, which means it needs to be at the same level as other elements (including full screen elements) in order to work properly.
The following are the markers:
<div> <div>Hero Zone</div> <div>Adhesive zone</div> <div>Full screen area</div> <div>Full screen area</div> </div>
Create sticky elements
Creating sticky elements in a CSS grid layout is very simple. We add position: sticky
and top: 0
offsets to .box--sticky
element, indicating where it starts pasting. Note that we only make the elements sticky when the window width is greater than 768px.
@media screen and (min-width: 768px) { .box--sticky { position: sticky; top: 0; } }
It should be noted that when position: sticky
is used with overflow: auto
, there are known sticky positioning problems in Safari. This is explained in the Known Issues section of the Caniuse website:
Setting to
overflow: auto
's parent element will preventposition: sticky
in Safari from working.
Not bad, it's easy. Next, let's solve the challenge of full-screen elements.
Solution 1: Pseudo-element
The first solution is the method I often use: absolutely positioned pseudo-elements that can extend from one side to the other. The trick here is to use negative offsets.
If we are talking about centering, the calculation is quite simple:
.box--bleed { max-width: 600px; margin-right: auto; margin-left: auto; padding: 20px; position: relative; } .box--bleed::before { content: ""; background-color: dodgerblue; position: absolute; top: 0; bottom: 0; right: calc((100vw - 100%) / -2); left: calc((100vw - 100%) / -2); }
In short, the negative offset is the window width ( 100vw
) minus the element width ( 100%
) and then divide by -2 because we need two negative offsets.
It should be noted that there is a known bug when using 100vw
, and the Caniuse website also explained this:
Currently all browsers except Firefox are mistakenly thinking that
100vw
is the entire page width, including the vertical scroll bar, which can result in horizontal scroll bars whenoverflow: auto
is set.
Now let's create full screen elements without the content being centered. If you watch the video again, you will notice that there is no content under the sticky element. We don't want sticky elements to overlap with content, which is why there is no centered content in this particular layout.
First, we will create the grid:
.grid { display: grid; grid-gap: var(--gap); grid-template-columns: var(--cols); max-width: var(--max-width); margin-left: auto; margin-right: auto; }
We use custom properties that allow us to redefine the maximum width, gap, and grid columns without redeclaring the properties. In other words, we redeclare the variable values instead of redeclaring grid-gap
, grid-template-columns
and max-width
properties:
:root { --gap: 20px; --cols: 1fr; --max-width: calc(100% - 2 * var(--gap)); } @media screen and (min-width: 768px) { :root { --max-width: 600px; --aside-width: 200px; --cols: 1fr var(--aside-width); } } @media screen and (min-width: 980px) { :root { --max-width: 900px; --aside-width: 300px; } }
On a window with a width of 768px and above, we define two columns: one with a fixed width ( --aside-width
), the other with a remaining space ( 1fr
), and the maximum width of the grid container ( --max-width
).
On windows less than 768px, we define a column and gap. The maximum width of the grid container is 100% of the viewport, minus the gap on both sides.
Now is the wonderful part. The content is not centered on the larger window, so the calculation is not as simple as you think. Here's what it looks like:
.box--bleed { position: relative; z-index: 0; } .box--bleed::before { content: ""; display: block; position: absolute; top: 0; bottom: 0; left: calc((100vw - (100% var(--gap) var(--aside-width))) / -2); right: calc(((100vw - (100% - var(--gap) var(--aside-width))) / -2) - (var(--aside-width))); z-index: -1; }
Instead of using 100% of the parent element width, we consider the gap and the width of the sticky element. This means that the content width in the full screen element does not exceed the boundary of the hero element. This way, we ensure that the sticky elements do not overlap with any important information.
The left offset is relatively simple because we only need to subtract the element width ( 100%
), gap ( --gap
) and sticky elements ( --aside-width
) from the window width ( 100vw
).
left: (100vw - (100% var(--gap) var(--aside-width)) / -2);
The right offset is more complicated because we have to add the width of the sticky element to the previous calculation, --aside-width
, and gap, --gap
:
right: ((100vw - (100% var(--gap) var(--aside-width))) / -2) - (var(--aside-width) var(--gap));
Now we can make sure that the sticky element does not overlap anything in the full screen element.
Here is a solution that contains horizontal bugs:
Here is a solution that includes horizontal bug fixes:
The fix is to hide the body's x-axis overflow, which is usually a good idea:
body { max-width: 100%; overflow-x: hidden; }
This is a completely feasible solution and we can end there. But what's the fun of this? There is usually more than one way to accomplish something, so let's look at another.
Solution 2: Fill calculation
Instead of using centered mesh containers and pseudo-elements, we can achieve the same effect by configuring the mesh. Let's start by defining the grid, like we did last time:
.grid { display: grid; grid-gap: var(--gap); grid-template-columns: var(--cols); }
Similarly, we use custom properties to define gaps and template columns:
:root { --gap: 20px; --gutter: 1px; --cols: var(--gutter) 1fr var(--gutter); }
We display three columns on windows smaller than 768px. The middle column takes up as much space as possible, while the other two columns are only used for forced horizontal gaps.
@media screen and (max-width: 767px) { .box { grid-column: 2 / -2; } }
Note that all grid elements are placed in the middle column.
On windows larger than 768px, we define a --max-width
variable that limits the width of the inner column. We also define --aside-width
, which is the width of the sticky element. Again, this ensures that the sticky element does not position over anything within the full screen element.
:root { --gap: 20px; } @media screen and (min-width: 768px) { :root { --max-width: 600px; --aside-width: 200px; --gutter: calc((100% - (var(--max-width))) / 2 - var(--gap)); --cols: var(--gutter) 1fr var(--aside-width) var(--gutter); } } @media screen and (min-width: 980px) { :root { --max-width: 900px; --aside-width: 300px; } }
Next, we will calculate the margin width. The calculation formula is:
--gutter: calc((100% - (var(--max-width))) / 2 - var(--gap));
… 100%
of which is the window width. First, we subtract the maximum width of the inner column from the window width. We then divide the result by 2 to create the margin. Finally, we subtract the grid gap to get the correct width of the margin column.
Now let's push .box--hero
element aside so that it starts with the first column of the grid:
@media screen and (min-width: 768px) { .box--hero { grid-column-start: 2; } }
This will automatically push the sticky box so it follows the hero element. We can also clearly define the position of the sticky box as follows:
.box--sticky { grid-column: 3 / span 1; }
Finally, let's create a full screen element by setting grid-column
to 1 / -1
. This tells the element to start the content from the first grid item and spans to the last grid item.
@media screen and (min-width: 768px) { .box--bleed { grid-column: 1 / -1; } }
To center content, we will calculate the left and right padding. The left side fill is equal to the size of the margin column plus the grid gap. The right fill is equal to the size of the left fill, plus another grid gap and the width of the sticky element.
@media screen and (min-width: 768px) { .box--bleed { padding-left: calc(var(--gutter) var(--gap)); padding-right: calc(var(--gutter) var(--gap) var(--gap) var(--aside-width)); } }
Here is the final solution:
I prefer this solution because it does not use the window unit in question.
I like CSS calculations. Using math is not always straightforward, especially when combining different units, such as 100%
. Finding out what 100%
means is half the job.
I also like to use CSS to solve simple but complex layouts, like this one. Modern CSS has native solutions—such as mesh, sticky positioning and computing—eliminate complex and rather heavy JavaScript solutions. Let's leave the dirty work to the browser!
Do you have a better solution or a different approach to this? I'd love to hear what you think.
The above is the detailed content of How to Get Sticky and Full-Bleed Elements to Play Well Together. For more information, please follow other related articles on the PHP Chinese website!

CSS Grid is a powerful tool for creating complex, responsive web layouts. It simplifies design, improves accessibility, and offers more control than older methods.

Article discusses CSS Flexbox, a layout method for efficient alignment and distribution of space in responsive designs. It explains Flexbox usage, compares it with CSS Grid, and details browser support.

The article discusses techniques for creating responsive websites using CSS, including viewport meta tags, flexible grids, fluid media, media queries, and relative units. It also covers using CSS Grid and Flexbox together and recommends CSS framework

The article discusses the CSS box-sizing property, which controls how element dimensions are calculated. It explains values like content-box, border-box, and padding-box, and their impact on layout design and form alignment.

Article discusses creating animations using CSS, key properties, and combining with JavaScript. Main issue is browser compatibility.

Article discusses using CSS for 3D transformations, key properties, browser compatibility, and performance considerations for web projects.(Character count: 159)

The article discusses using CSS gradients (linear, radial, repeating) to enhance website visuals, adding depth, focus, and modern aesthetics.

Article discusses pseudo-elements in CSS, their use in enhancing HTML styling, and differences from pseudo-classes. Provides practical examples.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

Atom editor mac version download
The most popular open source editor

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.

SublimeText3 Chinese version
Chinese version, very easy to use
