display: flow-root, a clearfix replacement

display: flow-root

The post talks about elements of a W3C candidate recommendation, CSS Display Module Level 3. It’s possible but highly unlikely, that things will change before the recommendation is finalized.

Most developers (myself included) will be familiar with some values for the display property:

  • block
  • inline
  • inline-block
  • grid
  • flex

And we use these in most of our everyday design, dating to the “age of floats” design philosophy. To see the full list check out the MDN article on the display property.

Using flow-root. The end of clearfix?

Rachel Andrew’s The end of the clearfix hack? explains a new way to avoid the clear fix hack.

From Clearfix: A Lesson in Web Development Evolution

The clearfix, for those unaware, is a CSS hack that solves a persistent bug that occurs when two floated elements are stacked next to each other. When elements are aligned this way, the parent container ends up with a height of 0, and it can easily wreak havoc on a layout. All you might be trying to do is position a sidebar to the left of your main content block, but the result would be two elements that overlap and collapse on each other. To complicate things further, the bug is inconsistent across browsers. The clearfix was invented to solve all that.

The idea is that using the ::after pseudo element we add attributes that fill force the clearing of the floats and get us the layout we want.

The most basic clearfix looks like this:

.container::after {
  content: "";
  display: block;
  clear: both;
}

display: flow-root replaces the clearfix with a single attribute. it creates a new block formatting context for the element using flow layout formatting, fixing the layout without needing additional attributes.

Using flow-root the element itself now looks like this:

.container {
  display: flow-root;
}

We don’t need to use the ::after pseudo-element to generate a clearfix anymore.

To see what issues display: flow-root solves see this Codepen from Rachel Andrew.

Browser support

Browser support for display:flow-root is not quite there yet. Current (non-Chromium versions) of Edge and iOS Safari support the feature, although desktop Safari does.

Data on support for the flow-root feature across the major browsers from caniuse.com
Data on support for the flow-root feature across the major browsers from caniuse.com

Until support is normalized code defensively and either use @support to target browsers that support the feature and use the clearfix for browsers that don’t support either @supports or display: flow-root

Adding transparency to hex colors

One thing hidden somewhere in the CSS specifications is the fact that you can use four or eight digits to represent a hexadecimal color, three or six to represent the color and one or two to represent the alpha transparency. For clarity’s sake, the post will only cover the eight-digit version.

What is this?

If you’re familiar with the RGB/RGBA color space in CSS you will see two different types of color, one solid color and one with some level of transparency.

RGB colors use values from 0 to 255 or 1 to 100% to represent color and values from 0 to 1 to represent transparency.

The example below shows an example of RGB and RGBA colors and how they look in the browser.

Partially transparent: rgba(6,52,164, .45)

Fully Opaque: rgba(6,52,164, 1)

Hex and Hex + Transparency Colors

For most developers (myself among them), Hexadecimal (hex) colors are the first type of colors we’ve used with CSS.

It came as a surprise that you could expand the format to include alpha channel transparency.

The following examples show three of the syntaxes available for Hex colors:

  1. The traditional 6 digit syntax
  2. The “new” 8 color syntax using full opacity
  3. The “new” syntax using transparency

Fully Opaque:; #0634a4

Fully Opaque (with trasparency): #0634a4ff

Partially transparent: #0634a466

The hardest part of this is to figure out how transparency works in hexadecimal numbers.

Remember that RGBA colors work with transparency between 0 and 1, but working with values from 00 to FF is conceptually harder (at least for me). It’ll take a lot of trial and error to get the numbers right.

Browser support

Browser support is pretty good with Edge, the last outlier coming into the fold once the Chromium version of Edge goes into regular release.


Data on support for the css-rrggbbaa feature across the major browsers from caniuse.com

Difference between inline and inline-block

As I was working on a side project, the same one where I was using buttons I saw examples using display: inline-block used in the button styles.

Why should I use inline-block instead of inline styles? What difference does it make?

Difference between inline-block and inline

display: inline-block respect top and bottom margins & paddings. display: inline, doesn’t.

In the example below, we use both inline and inline-block elements in the same paragraph to illustrate the process.

<p>Cheese and wine ricotta danish fontina.
Brie cheesy grin paneer squirty cheese taleggio
cheesecake <span class="inline-block-box">goat
taleggio</span> <span class="inline-box">goat
taleggio</span>. Bavarian
bergkase emmental fromage cheesecake
cheese slices cheesy grin queso caerphilly.</p>

The styles for the span elements are identical except for the display attribute.

Again, the difference is that inline-block will honor dimensions and padding but inline will not.

span.inline-block-box {
  display: inline-block;
  width: 100px;
  height: 100px;
  padding: 1em;
  background-color: rebeccapurple;
  color: white;
}

span.inline-box {
  display: inline;
  width: 100px;
  height: 100px;
  padding: 1em;
  background-color: rebeccapurple;
  color: white;
}

You can see multiple examples using the styles described above in Codepen: https://codepen.io/caraya/pen/wvvpEQo

The first example uses inline-block for two span elements.

The second example uses inline for both span elements

The last example combines the two. It uses inline-block for the first span and inline for the second.

Why would we use inline-block?

There may be times when we want to style inline elements with attributes that will only work with inline-block elements.

Styling buttons

I was working on a side project where I have a series of buttons but when I tried to style them the CSS did nothing.

In doing research, I discovered several things you can do and that I wasn’t doing and things that I was doing wrong.

I’m working with SCSS/SASS because it’s easier for me to nest rules and figure out associations between elements. It will be converted to CSS at build time.

Quick Reset

The example I’ll use in the rest of the post uses a reset. This could be used in addition to normalize.css or Eric Meyer’s CSS Reset or as a standalone quick reset for all button elements.

button {
  background-color: transparent;
  border: none;
  cursor: pointer;
  color: inherit;
  font: inherit;
  padding: 0;
}

Styling buttons

I start with setting the buttons to be inline-block rather than inline or block to keep being able to style and align them together if I so choose. (1)

display: inline-block brought a new way to create side by side boxes that collapse and wrap properly depending on the available space in the containing element.

From: Inline vs Inline-Block Display in CSS

We align the text and remove any existing underline.

In the next block, we define margins, border-radius. It appears that this is the only way to size buttons. (2)

Next, we define the color for the text and background. In this case, we use a linear-gradient as an experiment. (3)

.btn {
  display: inline-block; /* 1 */
  text-align: center; /* 1 */
  text-decoration: none; /* 1 */

  margin: 2px 0; /* 2 */
  border-radius: 4px; /* 2 */
  padding: 1em 3em; /* 2 */

  color: #ffffff; /* 3 */
  background:
    linear-gradient(#9198e5, #e66465);/* 3 */

The two pseudo-classes, :active and :hover define two possible states for the button.

:active indicates the styles active when the user clicks the button. For this state, we move the element to the right and saturate the color (make it darker) and add an outline. (4)

  &:active { /* 4 */
    transform: translateX(10px);
    filter: saturate(300%);
    outline: 3px solid blue;
  }

:hover provides the styles for when the user hovers over the button. In this state, we reverse the colors for the background and text.

  &:hover { /* 5 */
    color: white;
    border-color: currentColor;
    background: transparent;
    background-color: lightblue;
    outline: 3px solid blue;
  }
}

Accessibility

One additional thing to consider is accessibility.

Wes Bos asked on Twitter this question about button accessibility.

In particular pay attention to Andy Bell’s answer in the Gist he provided

Conclusion

This button is a test. All colors and actions are done as a test and will most likely change for production. You can see a working example in this codepen

Shapes in CSS: Freeing the layout

Shapes allow you to wrap text around parts of an image or a predefined shape. Using these shapes we can change the way text looks on the screen

Shape without image

In its most simple way, we can wrap text around an invisible shape defined as we would a clip-path.

The HTML defines an empty div element that will hold the shape we define in CSS.

<div class="coffee"></div>
<p>Dark, lungo, café au lait in latte fair
trade blue mountain strong, redeye sugar
seasonal café au lait Turkish. Black mug
variety, cappuccino, single-shot body sit
grounds coffee whipped Turkish et, skinny,
doppio so filter Turkish spoon affogato rich.

The CSS for the .cofee div we defined in markup holds the shape that the text will flow around.

The element must have explicit dimensions (width and height) and must be floated.

The shape-outside attribute describes the shape that the text will wrap around.

.coffee {
  shape-outside: circle(40%);
  float: left;
  height: 300px;
  width: 300px;
}

The examples, so far have only used a single shape, but you can use other values for shape-outside as shown in the list below, taken from (MDN).

none
The float area is unaffected. Inline content wraps around the element’s margin box, like usual.
<shape-box>
The float area is computed according to the shape of a float element’s edges (as defined by the CSS box model). This can be margin-box, border-box, padding-box, or content-box. The shape includes any curvature created by the border-radius property.
margin-box
Defines the shape enclosed by the outside margin edge. The corner radii of this shape are determined by the corresponding border-radius and margin values.
border-box
Defines the shape enclosed by the outside border edge. The shape follows the normal border radius shaping rules for the outside of the border.
padding-box
Defines the shape enclosed by the outside padding edge. The shape follows the normal border radius shaping rules for the inside of the border.
content-box
Defines the shape enclosed by the outside content edge. Each corner radius of this box is the larger of 0 or border-radius - border-width - padding.
<basic-shape>
The float area is computed based on the shape created by of one of inset(), circle(), ellipse(), or polygon().
<image>
The float area is extracted and computed based on the alpha channel of the specified <image> as defined by shape-image-threshold.

Shape with an image

We can combine shapes with images to get a graphical effect of the text wrapping around an image rather than around a space.

In this example, we add an image of a coffee cup and give it a class to reference it from CSS.

<h1>I'm nice, once I've
had my coffee</h1>

<img class="coffee"
src='path/to/coffee2.png' alt='coffee cup'>
<p>Dark, lungo, café au lait in latte
fair trade blue mountain strong, redeye
sugar seasonal café au lait turkish.
Black mug variety, cappuccino, single shot
 body sit grounds coffee whipped
 Turkish et, skinny …</p>

The CSS for the image (.coffee) uses shape-outside and shape-image-threshold.

When you use an image as the value for shape-outside the shape is defined by the pixels whose alpha value is greater than the threshold.

.coffee {
  shape-outside: circle(50%);
  shape-image-threshold: 0.5;
  float: left;
}

We can play with shape-outside to place text on top of the image and use images of arbitrary complexity to make our text “speak” in the voice we want.

Shapes and multiple images

Another way we can use shapes to make text flow between shapes creating custom layouts that move us outside boxes, at least visually.

The example adds two empty divs (coffee and coffee2).

<div class="coffee"></div>
<div class="coffee2"></div>
<p>Dark, lungo, café au lait in latte fair
 trade blue mountain strong, redeye sugar
 seasonal café au lait Turkish. Black mug
 variety, cappuccino, single-shot body sit
 grounds coffee whipped Turkish et, skinny,
 doppio so filter Turkish spoon affogato
 rich. Steamed roast, froth fair trade
 chicory a dripper, Turkish, extra milk,
 wings, milk dark Viennese, and est, filter,
 caffeine café au lait ut aromatic aged.</p>

The CSS defines two identical properties that create the same space on the left and right sides.

We could abstract the common elements to a third class that we can reuse but for this example, I’m ok with the duplication.

.coffee {
  shape-outside: circle(50%);
  float: left;
  height: 300px;
  width: 300px;
}

.coffee2 {
  shape-outside: circle(50%);
  float: right;
  height: 300px;
  width: 300px;
}

You can see the final product in this Codepen

A more complex example

When shapes were first released there was a companion specification for regions. This demo from the Adobe Web Platform team uses both.

Sadly, Regions are not supported in any browser other than old Edge so instead, I chose to present a video from Adobe, showing the project.