A whole bunch of years ago, we posted on this idea here on CSS-Tricks. We figured it was time to update that and do the subject justice.
Imagine a scenario where you need to split a layout in half. Content on the left and content on the right. Basically two equal height columns are needed inside of a container. Each side takes up exactly half of the container, creating a distinct break between one. Like many things in CSS, there are a number of ways to go about this and we’re going to go over many of them right now!
Update (Oct. 25, 2024): Added an example that uses CSS Anchor Positioning.
Using Background Gradient
One simple way we can create the appearance of a changing background is to use gradients. Half of the background is set to one color and the other half another color. Rather than fade from one color to another, a zero-space color stop is set in the middle.
.container {
background: linear-gradient(
to right,
#ff9e2c 0%,
#ff9e2c 50%,
#b6701e 50%,
#b6701e 100%
);
}
This works with a single container element. However, that also means that it will take working with floats or possibly some other layout method if content needs to fill both sides of the container.
Using Absolute Positioning
Another route might be to set up two containers inside of a parent container, position them absolutely, split them up in halves using percentages, then apply the backgrounds. The benefit here is that now we have two separate containers that can hold their own content.
Absolute positioning is sometimes a perfect solution, and sometimes untenable. The parent container here will need to have a set height, and setting heights is often bad news for content (content changes!). Not to mention absolute positioned elements are out of the document flow. So it would be hard to get this to work while, say, pushing down other content below it.
Using (fake) Tables
Yeah, yeah, tables are so old school (not to mention fraught with accessibility issues and layout inflexibility). Well, using the display: table-cell;
property can actually be a handy way to create this layout without writing table markup in HTML. In short, we turn our semantic parent container into a table, then the child containers into cells inside the table — all in CSS!
You could even change the display properties at breakpoints pretty easily here, making the sides stack on smaller screens. display: table;
(and friends) is supported as far back as IE 8 and even old Android, so it’s pretty safe!
Using Floats
We can use our good friend the float
to arrange the containers beside each other. The benefit here is that it avoids absolute positioning (which as we noted, can be messy).
In this example, we’re explicitly setting heights to get them to be even. But you don’t really get that ability with floats by default. You could use the background gradient trick we already covered so they just look even. Or look at fancy negative margin tricks and the like.
Also, remember you may need to clear the floats on the parent element to keep the document flow happy.
Using Inline-Block
If clearing elements after floats seems like a burden, then using display: inline-block
is another option. The trick here is to make sure that the elements for the individual sides have no breaks or whitespace in between them in the HTML. Otherwise, that space will be rendered as a literal space and the second half will break and fall.
Again there is nothing about inline-block that helps us equalize the heights of the sides, so you’ll have to be explicit about that.
There are also other potential ways to deal with that spacing problem described above.
Using Flexbox
Flexbox is a pretty fantastic way to do this, just note that it’s limited to IE 10 and up and you may need to get fancy with the prefixes and values to get the best support.
Using this method, we turn our parent container into a flexible box with the child containers taking up an equal share of the space. No need to set widths or heights! Flexbox just knows what to do, because the defaults are set up perfectly for this. For instance, flex-direction: row;
and align-items: stretch;
is what we’re after, but those are the defaults so we don’t have to set them. To make sure they are even though, setting flex: 1;
on the sides is a good plan. That forces them to take up equal shares of the space.
In this demo we’re making the side flex containers as well, just for fun, to handle the vertical and horizontal centering.
Using Grid Layout
For those living on the bleeding edge, the CSS Grid Layout technique is like the Flexbox and Table methods merged into one. In other words, a container is defined, then split into columns and cells which can be filled flexibly with child elements.
CSS Anchor Positioning
This started rolling out in 2024 and we’re still waiting for full browser support. But we can use CSS Anchor Positioning to “attach” one element to another — even if those two elements are completely unrelated in the markup.
The idea is that we have one element that’s registered as an “anchor” and another element that’s the “target” of that anchor. It’s like the target element is pinned to the anchor. And we get to control where we pin it!
.anchor {
anchor-name: --anchor;
}
.target {
anchor-position: --anchor;
position: absolute; /* required */
}
This sets up an .anchor
and establishes a relationship with a .target
element. From here, we can tell the target which side of the anchor it should pin to.
.anchor {
anchor-name: --anchor;
}
.target {
anchor-position: --anchor;
position: absolute; /* required */
left: anchor(right);
}
Isn’t it cool how many ways there are to do things in CSS?