text-decoration – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Fri, 25 Feb 2022 15:28:35 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.1 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 text-decoration – CSS-Tricks https://css-tricks.com 32 32 45537868 When to Avoid the text-decoration Shorthand Property https://css-tricks.com/when-to-avoid-css-text-decoration-shorthand/ https://css-tricks.com/when-to-avoid-css-text-decoration-shorthand/#comments Fri, 25 Feb 2022 15:28:33 +0000 https://css-tricks.com/?p=363619 In my recent article about CSS underline bugs in Chrome, I discussed text-decoration-thickness and text-underline-offset, two relatively new and widely-supported CSS properties that give us more control over the styling of underlines.

Let me demonstrate the usefulness of …


When to Avoid the text-decoration Shorthand Property originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In my recent article about CSS underline bugs in Chrome, I discussed text-decoration-thickness and text-underline-offset, two relatively new and widely-supported CSS properties that give us more control over the styling of underlines.

Let me demonstrate the usefulness of text-decoration-thickness on a simple example. The Ubuntu web font has a fairly thick default underline. We can make this underline thinner like so:

:any-link {
  text-decoration-thickness: 0.08em;
}
Showing two links, a default and one that decreases the text-decoration-thickness.

/explanation Throughout this article, I will use the :any-link selector instead of the a element to match hyperlinks. The problem with the a tag as a selector is that it matches all <a> elements, even the ones that don’t have a href attribute and thus aren’t hyperlinks. The :any-link selector only matches <a> elements that are hyperlinks. Web browsers also use :any-link instead of a in their user agent stylesheets.

Hover underlines

Many websites, including Google Search and Wikipedia, remove underlines from links and only show them when the user hovers a link. Removing underlines from links in body text is not a good idea, but it can make sense in places where links are more spaced apart (navigation, footer, etc.). With that being said, here’s a simple implementation of hover underlines for links in the website’s header:

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline;
}

But there’s a problem. If we tested this code in a browser, we’d notice that the underlines in the header have the default thickness, not the thinner style that we declared earlier. Why did text-decoration-thickness stop working after we added hover underlines?

Let’s look at the full CSS code again. Can you think of a reason why the custom thickness doesn’t apply to the hover underline?

:any-link {
  text-decoration-thickness: 0.08em;
}

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline;
}

The reason for this behavior is that text-decoration is a shorthand property and text-decoration-thickness its associated longhand property. Setting text-decoration to none or underline has the side effect of re-initializing the other three text decoration components (thickness, style, and color). This is defined in the CSS Text Decoration module:

The text-decoration property is a shorthand for setting text-decoration-line, text-decoration-thickness, text-decoration-style, and text-decoration-color in one declaration. Omitted values are set to their initial values.

You can confirm this in the browser’s DevTools by selecting one of the hyperlinks in the DOM inspector and then expanding the text-decoration property in the CSS pane.

DevTools screenshot showing text-decoration styles on the :any-link pseudo-selector.

In order to get text-decoration-thickness to work on hover underlines, we’ll have to make a small change to the above CSS code. There are actually multiple ways to achieve this. We could:

  • set text-decoration-thickness after text-decoration,
  • declare the thickness in the text-decoration shorthand, or
  • use text-decoration-line instead of text-decoration.

Choosing the best text-decoration option

Our first thought might be to simply repeat the text-decoration-thickness declaration in the :hover state. It’s a quick and simple fix that indeed works.

/* OPTION A */

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline;
  text-decoration-thickness: 0.08em; /* set thickness again */
}

However, since text-decoration is a shorthand and text-decoration-thickness is its associated longhand, there really should be no need to use both at the same time. As a shorthand, text-decoration allows setting both the underline itself and the underline’s thickness, all in one declaration.

/* OPTION B */

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline 0.08em; /* set both line and thickness */
}

If this code looks unfamiliar to you, that could be because the idea of using text-decoration as a shorthand is relatively new. This property was only subsequently turned into a shorthand in the CSS Text Decoration module. In the days of CSS 2, text-decoration was a simple property.

Unfortunately, Safari still hasn’t fully caught up with these changes. In the WebKit browser engine, the shorthand variant of text-decoration remains prefixed (-webkit-text-decoration), and it doesn’t support thickness values yet. See WebKit bug 230083 for more information.

This rules out the text-decoration shorthand syntax. The above code won’t work in Safari, even if we added the -webkit- prefix. Luckily, there’s another way to avoid repeating the text-decoration-thickness declaration.

When text-decoration was turned into a shorthand, a new text-decoration-line longhand was introduced to take over its old job. We can use this property to hide and show the underline without affecting the other three text decoration components.

/* OPTION C */

header :any-link {
  text-decoration-line: none;
}

header :any-link:hover {
  text-decoration-line: underline;
}

Since we’re only updating the line component of the text-decoration value, the previously declared thickness remains intact. I think that this is the best way to implement hover underlines.

Be aware of shorthands

Keep in mind that when you set a shorthand property, e.g., text-decoration: underline, any missing parts in the value are re-initialized. This is also why styles such as background-repeat: no-repeat are undone if you set background: url(flower.jpg) afterwards. See the article “Accidental CSS Resets” for more examples of this behavior.


When to Avoid the text-decoration Shorthand Property originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/when-to-avoid-css-text-decoration-shorthand/feed/ 2 363619
The CSS from-font Value Explained in 4 Demos https://css-tricks.com/from-font-value-text-decoration-thickness/ https://css-tricks.com/from-font-value-text-decoration-thickness/#respond Fri, 28 Jan 2022 18:37:52 +0000 https://css-tricks.com/?p=362382 I was doing my Advent of UI Components, and I stumbled upon the from-font value for the text-decoration-thickness CSS property. I was curious about it, so I did a little research and I think what I found (and learned) …


The CSS from-font Value Explained in 4 Demos originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I was doing my Advent of UI Components, and I stumbled upon the from-font value for the text-decoration-thickness CSS property. I was curious about it, so I did a little research and I think what I found (and learned) is both interesting and worth sharing.

About the from-font value

Here’s how MDN defines the from-font value:

If the font file includes information about a preferred thickness, use that value. If the font file doesn’t include this information, behave as if auto was set, with the browser choosing an appropriate thickness.

So, the from-font value is used only if the font file has the definition for the thickness of the line. Otherwise, browsers use the auto value, which tells the browser to choose the thickness. I wanted to find out how that works, so I made a few demos comparing it to the other values.

Demo 1: text-decoration-thickness: auto

In the first demo, I wanted to see how the auto value for thickness works with under, over, and strikethrough lines for the default font family.

I didn’t find anything particularly interesting here, except that some combinations don’t work very well for strikethrough text (if you ask me). For example, using a wavy decoration with strikethrough isn’t readable, but that might be the desired output in some scenarios, I guess.

Demo 2: text-decoration-thickness: 0px

In the second demo, I wanted to see how the text works with thin lines.

The lines work with paragraphs or smaller text, but the thin strikethrough line doesn’t work very well with large text as the strikethrough line is hard to detect.

Showing the from-font value on larger text. The text is black and the line through the text is thin and barely noticeable.

I also learned that you cannot set the line thickness below 1px. In the demo, the line thickness is set to 0px, but the browser renders a 1px line anyway.

Demo 3: text-decoration-thickness: from-font and font-weight

Next, I wanted to see if the text-decoration-thickness: from-font declaration changes with the font weight. On the left, the value is set to from-font; on the right, the value is set to auto.

The from-font value doesn’t seem to follow changes to the text’s font weight, at least not with when Roboto is the font family. There is no difference between how big or bold the text is set. The line thickness is the same if the value is set to from-font.

It is worth noting that Firefox renders the line thickness the same for both values, so my guess is that Firefox actually uses the from-font value for the auto value.

Demo 4: text-decoration-thickness: from-font and font-family

In this final demo, I wanted to see how the from-font value works with different font families. It doesn’t impact the paragraphs or the smaller font sizes because it renders the smallest value, 1px. The difference is visible for the bigger font sizes, like default <h1> elements, but only if you look very closely. Also, the strikethrough line is once again too thin on bigger text. This is something that font designers and developers might consider when designing and defining fonts.

Browser support

You can most certainly use the text-decoration-thickness property today since most modern browsers support this property.

So, should you use it?

Although the from-font value might seem like a good idea, I don’t think it should be used just yet. There are too many inconsistencies with the default text-decoration-thickness value across the browsers (which Šime Vidas has covered in great depth), so it is no surprise that the from-font value is still not working that well. Maybe the from-font value should be defined in percentages or some other relative unit so that it changes with the font size. Maybe font designers feel that it shouldn’t work that way. Either way, it seems like more discussion is warranted to nail down the property value’s default behavior and how it renders.

I am using the from-font value on my personal site for the link underlines in the articles, and I think it works great. The line is subtle, but it still communicates the interaction.

I look forward to seeing more options for the text-decoration-thickness in the future.


The CSS from-font Value Explained in 4 Demos originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/from-font-value-text-decoration-thickness/feed/ 0 362382
CSS Underlines Are Too Thin and Too Low in Chrome https://css-tricks.com/css-underlines-are-too-thin-and-too-low-in-chrome/ https://css-tricks.com/css-underlines-are-too-thin-and-too-low-in-chrome/#comments Tue, 04 Jan 2022 15:30:18 +0000 https://css-tricks.com/?p=359838 I’ve encountered two bugs in Chrome while testing the new CSS text-decoration-thickness and text-underline-offset properties, and I want to share them with you here in this article.

Table of Contents


CSS Underlines Are Too Thin and Too Low in Chrome originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I’ve encountered two bugs in Chrome while testing the new CSS text-decoration-thickness and text-underline-offset properties, and I want to share them with you here in this article.

Table of Contents

First, let’s acknowledge one thing:

Default underlines are inconsistent

Let’s add a text link to a plain web page, set its font-family to Arial, and compare the underlines across browsers and operating systems.

From left to right: Chrome, Safari, and Firefox on macOS; Safari on iOS; Chrome, and Firefox on Windows; Chrome, and Firefox on Android.

As you can see, the default underline is inconsistent across browsers. Each browser chooses their own default thickness and vertical position (offset from the baseline) for the underline. This is in line with the CSS Text Decoration module, which specifies the following default behavior (auto value):

The user agent chooses an appropriate thickness for text decoration lines. […] The user agent chooses an appropriate offset for underlines.

Luckily, we can override the browsers’ defaults

There are two new, widely supported CSS properties that allow us to precisely define the thickness and offset for our underlines:

With these properties, we can create consistent underlines even across two very different browsers, such as the Gecko-based Firefox on Android and the WebKit-based Safari on macOS.

h1 {
  text-decoration: underline;
  text-decoration-thickness: 0.04em;
  text-underline-offset: 0.03em;
}
Top row: the browsers’ default underlines; bottom row: consistent underlines with CSS. (Demo)

Note: The text-decoration-thickness property also has a special from-font value that instructs browsers to use the font’s own preferred underline width, if available. I tested this value with a few different fonts, but the underlines were inconsistent.

OK, so let’s move on to the two Chrome bugs I noted earlier.

Chrome bug 1: Underlines are too thin on macOS

If you set the text-decoration-thickness property to a font-relative length value that computes to a non-integer pixel value, Chrome will “floor” that value instead of rounding it to the nearest integer. For example, if the declared thickness is 0.06em, and that computes to 1.92px, Chrome will paint a thickness of 1px instead of 2px. This issue is limited to macOS.

a {
  font-size: 2em; /* computes to 32px */
  text-decoration-thickness: 0.06em; /* computes to 1.92px */
}

In the following screenshot, notice how the text decoration lines are twice as thin in Chrome (third row) than in Safari and Firefox.

From top to bottom: Safari, Firefox, and Chrome on macOS. (Demo)

For more information about this bug, see Chromium issue #1255280.

Chrome bug 2: Underlines are too low

The text-underline-offset property allows us to precisely set the distance between the alphabetic baseline and the underline (the underline’s offset from the baseline). Unfortunately, this feature is currently not implemented correctly in Chrome and, as a result, the underline is positioned too low.

h1 {
  text-decoration: underline;
  text-decoration-color: #f707;

  /* disable “skip ink” */
  -webkit-text-decoration-skip: none; /* Safari */
  text-decoration-skip-ink: none;

  /* cover the entire descender */
  text-decoration-thickness: 0.175em; /* descender height */
  text-underline-offset: 0; /* no offset from baseline */
}

Because of this bug, it is not possible to move the underline all the way up to the baseline in Chrome.

From left to right: Safari, Firefox, and Chrome on macOS. View this demo on CodePen.

For more information about this bug, see Chromium issue #1172623.

Note: As you might have noticed from the image above, Safari draws underlines on top of descenders instead of beneath them. This is a WebKit bug that was fixed very recently. The fix should ship in the next version of Safari.

Help prioritize the Chrome bugs

The two new CSS properties for styling underlines are a welcome addition to CSS. Hopefully, the two related Chrome bugs will be fixed sooner rather than later. If these CSS features are important to you, make your voice heard by starring the bugs in Chromium’s bug tracker.

Sign in with your Google account and click the star button on issues #1172623 and #1255280.

CSS Underlines Are Too Thin and Too Low in Chrome originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/css-underlines-are-too-thin-and-too-low-in-chrome/feed/ 4 359838
Link Underlines That Animate Into Block Backgrounds https://css-tricks.com/link-underlines-that-animate-into-block-backgrounds/ https://css-tricks.com/link-underlines-that-animate-into-block-backgrounds/#comments Mon, 23 Sep 2019 20:13:09 +0000 https://css-tricks.com/?p=295935 It’s a cool little effect. The default link style has an underline (which is a good idea) and then on :hover you see the underline essentially thicken up turning into almost what it would have looked liked if you …


Link Underlines That Animate Into Block Backgrounds originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
It’s a cool little effect. The default link style has an underline (which is a good idea) and then on :hover you see the underline essentially thicken up turning into almost what it would have looked liked if you used a background-color on the link instead.

Here’s an example of the effect on the Superfriendly site:

A journey:

  • The Superfriendly site does it with box-shadow. Turning box-shadow: inset 0 -0.07em 0 #0078d6; into box-shadow: inset 0 -0.85em 0 #a2d5fe; with a transition. Andres Cuervo ported that idea to a Pen. (I forked it to fix the “start offset” idea that was broken-seeming to me on the original).
  • You might be tempted to draw the line with a pseudo-element that’s, say, absolutely positioned within the relatively positioned link. Then you animate its height or scaleY or something. Here’s that kind of idea. Your enemy here is going to be links that break onto new lines, which box-shadow seems to handle more elegantly.
  • Another idea would be using linear-gradient with hard color stops to kinda “fake” the drawing of a line that’s positioned to look like an underline. Then the gradient can be animated to cover the element on hover, probably by moving its background-position. Here’s that kind of idea and another example we wrote up a little while back. This handles line breaks nicer than the previous method.
  • The default text-decoration: underline; has a distinct advantage these days: text-decoration-skip-ink! It has become the default behavior for links to have the underlines deftly skip around the decenders in text, making for much nicer looking underlines than any of these techniques (also: borders) can pull off. There are properties that are somewhat new that you may not be aware of that give you more control over the underline that we have traditionally had, like text-decoration-color. But there is more, like thickness and offset, that make this effect possible! Miriam Suzanne has a demo of exactly this, which only works in Firefox Nightly at the moment, but should be making the rounds soon enough.

Summary: If you need to do this effect right now in the most browsers you can, the box-shadow technique is probably best. If it’s just an enhancement that can wait a bit, using text-decoration-thickness / text-decoration-offset / text-decoration-color with a transition is a better option for aesthetics, control, and being able to understand the code at first glance.


Link Underlines That Animate Into Block Backgrounds originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/link-underlines-that-animate-into-block-backgrounds/feed/ 3 295935
Decorating lines of text with box-decoration-break https://css-tricks.com/decorating-lines-of-text-with-box-decoration-break/ https://css-tricks.com/decorating-lines-of-text-with-box-decoration-break/#comments Tue, 08 May 2018 13:49:31 +0000 http://css-tricks.com/?p=270507 An institution’s motto, an artist’s intro, a company’s tagline, a community’s principle, a service’s greeting… all of them have one thing in common: they’re one brief paragraph displayed on a website’s home page — or at least the about page!…


Decorating lines of text with box-decoration-break originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
An institution’s motto, an artist’s intro, a company’s tagline, a community’s principle, a service’s greeting… all of them have one thing in common: they’re one brief paragraph displayed on a website’s home page — or at least the about page!

It’s rare that just one word or one line of text welcomes you to a website. So, let’s look at some interesting ways we could style the lines of a paragraph.

To see how things currently are, let’s try giving borders to all the lines of some text in an inline span and see how it looks:

<p><span>Hummingbirds are birds from...</span></p>
span {
  border: 2px solid;
}

See the Pen Broken inline box. by Preethi (@rpsthecoder) on CodePen.

The edges appear broken, which they technically are, as the inline box has been fragmented into multiple lines. But we can fix those broken edges with box-decoration-break!

The box-decoration-break property in CSS can decorate the edges of fragments of a broken inline box (as well as of a page, column, and region boxes).

Its value, clone, does that with the same design that appears in the box’s unbroken edges, and its default value, slice, does not copy the decorations at the edges, keeping the break very visible like you saw in the demo above.

Let’s try it:

span {
  border: 2px solid;
  box-decoration-break: clone;
}

See the Pen Broken inline box w/ box-decoration-break. by Preethi (@rpsthecoder) on CodePen.

The property affects not only the border but also the shadow, spacing, and background of the broken edges.

Let’s play with the background first. While writing the post on knockout text, I was working with the background-clip property and wanted to see if the design held up for multiple lines of text. It didn’t.

The background gradient I applied was not replicated in every line, and after clipping it, only the first one was left with a background. That is, unless box-decoration-break: clone is added:

<p><span>Singapore:<br>Lion City</span></p>
span {
  background-image: linear-gradient(135deg, yellow, violet);
  background-clip: text;
  color: transparent;
  padding: .5em;
  box-decoration-break: clone;
}

See the Pen Gradient multi-line text w/box-decoration-break. by Preethi (@rpsthecoder) on CodePen.

The background-clip property with the text value clips a background to the shape of its foreground text. Since we used box-decoration-break, the gradient background is shown and clipped uniformly across all the lines of the text.

Going back to the border, let’s see how its shape and shadow can be copied across the broken edges, along with padding:

<img src="tree.png">
<p><span>Supertrees are tree-like structures...</span></p>
<img src="tree.png">
<p><span>Supertrees are tree-like structures...</span></p>
span {
  background: rgb(230,157,231);
  border-radius: 50% 0%;
  box-shadow: 0 0 6px rgb(41,185,82), 0 0 3px beige inset;
  padding: .5em 1.3em;
  box-decoration-break: clone;
}

p:nth-of-type(2) span {
  background-clip: content-box;
}

See the Pen Inline border shape & shadow w/box-decoration-break. by Preethi (@rpsthecoder) on CodePen.

In the second paragraph of the demo, the background is cropped until the content box (background-clip: content-box). As you can see, the crop happens in the broken edges as well, because of box-decoration-break: clone.

Another way we can style borders is with images. You might see a gradient border around the lines of text below, covering the broken edges, if the browser you’re now using supports border-image and the application of box-decoration-break over its result.

<p><span>The Malaysia–Singapore Second Link...</span></p>
span {
  border: 2px solid;
  border-image: linear-gradient(45deg, #eeb075, #2d4944) 1;
  background: #eef6f3;
  padding: .5em 1.3em;
  box-decoration-break: clone;
}

See the Pen Inline border image w/ box-decoration-break. by Preethi (@rpsthecoder) on CodePen.

An additional behavior we can tap into for decorating individual lines is of outline’s. In supported browsers, box-decoration-break can add an outline to every line of the text, including the broken edges, which is useful for creating bicolored dashed borders.

<p><span>Cloud Forest replicates...</span></p>
span {
  outline: 2px dashed rgb(216,255,248);
  box-shadow: 0 0 0 2px rgb(39,144,198);
  background: #fffede;
  padding: .5em 1.3em;
  animation: 1s animateBorder ease infinite;
  box-decoration-break: clone;
}

@keyframes animateBorder{
  to{
    outline-color: rgb(39,144,198);
    box-shadow: 0 0 0 2px rgb(216,255,248);
  }
}

See the Pen Inline outline w/ box-decoration-break. by Preethi (@rpsthecoder) on CodePen.

As observed in the demo, box-decoration-break withstands animation.

Besides borders and backgrounds, box-decoration-break can also manage shapes applied over elements. There is not much use for it in inline boxes, and is maybe better used in a column or page box, although the application is not yet widely supported in browsers.

But to show an example of what that does, let’s try applying the clip-path property to the span.

The property clip-path itself is only fully supported by Firefox, so only in it you might see an expected outcome. But following are two images: the results of applying a circular clip path over the span, without and with box-decoration-break.

span {
  clip-path: circle(50% at 202.1165px 69.5px);
  ...
}
A screenshot of a span of text being highlighted in DevTools showing that text is split up in three lines and with uneven start and end points.
Circular clip-path on a span
span {
  clip-path: circle(50% at 202.1165px 69.5px);
  box-decoration-break: clone;
  ...
}
A screenshot of a span of text being highlighted in DevTools showing that text is split up in three lines and with even start points but uneven end points.
Circular clip-path on a span with box-decoration-break: clone

You’ll notice in the first image that the 50% radius value is derived from the width of the inline box (the longest line) where box-decoration-break is not used.

The second image shows how box-decoration-break: clone redefines the computed value for 50% by basing them on the widths of the individual lines while keeping the center same as before.

And here’s how the inset function of clip-path (an inset rectangle) applied over the span clips it without and with box-decoration-break:

span {
  clip-path: inset(0);
  ...
}
A screenshot of a span of text being highlighted in DevTools showing that text is all on one line but the span continues for three lines with even start points but uneven end points.
Inset clip-path on a span
span {
  clip-path: inset(0);
  box-decoration-break: clone;
  ...
}
Inset clip-path on a span with box-decoration-break: clone

Without box-decoration-break, only a portion of the first line that matches the length of the shortest is visible, and with box-decoration-break: clone, the first line is fully visible while the rest of the box is clipped.

So, maybe if you ever want to show only the first line and hide the rest, this can come in handy. But, as I mentioned before, this application is more suitable for other types of boxes than ones that are inline. Either way, I wanted to show you how it works.

Browser Support

As we’ve seen here, box-decoraton-break can be super useful and opens up a lot of possibilities, like creating neat text effects. The property enjoys a lot support with the -webkit prefix, but is still in Working Draft at the time of this writing and lacks any support in Internet Explorer and Edge. Here’s where you can vote for Edge support.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

ChromeFirefoxIEEdgeSafari
111*32No108*TP*

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
108*107108*16.3*

Wrapping Up

The box-decoration-break: clone copies any border, spatial, and background designs applied on a fragmented inline box’s unbroken edges to its broken ones. This creates an even design across all the lines of the text, decorating them uniformly and can be super useful for all those blurbs of text that we commonly use on websites.


Decorating lines of text with box-decoration-break originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/decorating-lines-of-text-with-box-decoration-break/feed/ 2 270507
Styling Underlines on the Web https://css-tricks.com/styling-underlines-web/ https://css-tricks.com/styling-underlines-web/#comments Mon, 10 Oct 2016 13:15:47 +0000 http://css-tricks.com/?p=245767 Styling the underlines that sit beneath links can be a tricky business, and I constantly forget what’s the best approach depending on the situation. Thankfully however, John Jameson gets us up to speed in this guest post.

There are a …


Styling Underlines on the Web originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Styling the underlines that sit beneath links can be a tricky business, and I constantly forget what’s the best approach depending on the situation. Thankfully however, John Jameson gets us up to speed in this guest post.

There are a bunch of different ways to style underlines. Maybe you remember the article Crafting link underlines on Medium. Medium wasn’t trying to do anything crazy; they just wanted to create a pretty normal-looking line below their text.

A thin, black underline with space around descenders
A thin, black underline with space around descenders—via Marcin Wichary, Crafting link underlines on Medium

It’s a pretty basic underline, but it’s a good size and it skips descenders too. Definitely nicer than most browsers’ default. Well, it turns out Medium had to go through a lot of trouble to get that style on the web. Two years later, it’s still just as hard to style a good-looking underline.

Goals

What’s wrong with just using text-decoration: underline? If we’re talking about the ideal scenario, an underline should be able to do the following:

  • Position itself below the baseline
  • Skip descenders
  • Change color, thickness, and style
  • Repeat across wrapped text
  • Work on any background

I think these are all pretty reasonable things to ask for, but as far as I know, there’s no intuitive way to achieve all of them in CSS.

Approaches

So what are all the different ways we can underline text on the web?

Here are the ones I can think of:

  • text-decoration
  • border-bottom
  • box-shadow
  • background-image
  • SVG filters
  • Underline.js (canvas)
  • text-decoration-*

Let’s go down the list one by one and talk about the good and bad parts of each approach.

text-decoration

text-decoration is the most straightforward way to underline text. You apply a single property and that’s all there is to it. At smaller sizes, it can look pretty decent, but increase the font size and the same line starts to feel clumsy.

See the demo.

The biggest problem with text-decoration is its lack of customizability. It uses the color and font size of whatever text its applied to and there’s no cross-browser way to change the style. More on that later.

Good
  • Easy to use
  • Positioned below the baseline
  • Skips descenders by default in Safari and iOS
  • Wraps across lines
  • Works on any background
Bad
  • Can’t skip descenders in other browsers
  • Can’t change color, thickness, or style

border-bottom

border-bottom offers a good balance between being quick and customizable. This approach uses a tried-and-true CSS border, which means you can change color, thickness, and style with ease.

This is what border-bottom looks like on inline elements:

See the demo.

The big gotcha is how far away the underline is from the text — it’s completely below the descenders. You can address that by making elements inline-block and reducing line-height, but then you lose the ability to wrap text. Good for single lines, but not much else.

See the demo.

Additionally, you can use text-shadow to cover up parts of the line near descenders, but you have to fake it by using the same color as whatever background it’s on. That means it works only for solid-color backgrounds and not gradients or images.

See the demo.

At this point, there are four properties styling a single underline. That’s a lot more work than text-decoration.

Good
  • Can skip descenders using text-shadow
  • Can change color, thickness, and style
  • Can transition and animate color and thickness
  • Wraps by default unless it’s an inline-block
  • Works on any background unless using text-shadow
Bad
  • Positioned far away and difficult to reposition
  • A lot of unrelated properties to get it just right
  • Janky text selection when using text-shadow

box-shadow

box-shadow draws an underline with two inset box shadows: one to create a rectangle and a second to cover it up. That means you’ll need a solid background for this to work.

See the Pen Underlines 5: box-shadow by John D. Jameson (@johndjameson) on CodePen.

You can use the same text-shadow trick to fake gaps between the underline and the text’s descenders. But if the line is a different color from the text — or even just thin enough — it doesn’t really clash like text-decoration does.

Good
  • Can be positioned below the baseline
  • Can skip descenders using text-shadow
  • Can change color and thickness
  • Wraps across lines
Bad
  • Can’t change style
  • Doesn’t work on any background

background-image

background-image comes the closest to everything we want and with the fewest gotchas. The idea is that you use linear-gradient and background-position to create an image that repeats itself horizontally across lines of text.

You’ll have to display: inline; this approach too.

See the demo.

This approach doesn’t have to use linear-gradient either. You can bring your own background image for some cool effects.

See the demo.

Good
  • Can be positioned below the baseline
  • Can skip descenders using text-shadow
  • Can change color, thickness (allows half pixels), and style
  • Works with custom images
  • Wraps across lines
  • Works on any background unless using text-shadow
Bad
  • The image can resize differently across resolutions, browsers, and zoom levels

SVG filters

Here’s an approach I’ve been toying around with: SVG filters. You can create an inline SVG filter element that draws a line and then expands the text to mask out parts of the line we want to be transparent. Then you can give the filter an an id and reference it in CSS with something like filter: url(‘#svg-underline’).

The advantage here is that the filter adds transparency without relying on text-shadow. That means you can skip descenders on top of any background, including gradients and background images! This one works only on a single line of text though, so heads-up on that.

See the demo.

Here’s what it looks like in Chrome and Firefox:

Browser support in IE, Edge, and Safari is problematic. It’s hard to test for SVG filter support in CSS. You can use @supports with filter, but that only tests if the reference works — not the applied filter itself. My approach ends up doing some pretty gross browser sniffing, so double heads-up on that too.

Pros
  • Positioned below the baseline
  • Skips descenders
  • Able to change color, thickness, and style
  • Works on any background
Cons
  • Doesn’t wrap across lines
  • Doesn’t work in IE, Edge, or Safari, but you can fall back to text-decoration. Safari’s underlines look good anyway.

Underline.js (Canvas)

Underline.js is fascinating. I think it’s super impressive what Wenting Zhang was able to do with JavaScript and some attention to detail. If you haven’t seen the Underline.js tech demo before, definitely stop reading for a minute and check it out. There’s a fascinating nine-minute-long talk on how it works, but I’ll give you the short version: it draws underlines with <canvas> elements. It’s a novel approach that works surprisingly well.

Despite the catchy name, Underline.js is a tech demo only. That means you won’t be able to drop it into any projects without modifying it a whole bunch first.

It’s worth bringing it up here as a proof of concept. <canvas> has the potential to create beautiful, interactive underlines, but you’ll have to write some custom JavaScript to get them working.

text-decoration-* properties

Remember the “more on that later” part? Well, here we are.

text-decoration works fine by itself, but you can add a few experimental properties to customize the way it looks:

  • text-decoration-color
  • text-decoration-skip
  • text-decoration-style

Just don’t get too excited. You know, browser support.

text-decoration-color

text-decoration-color lets you change an underline’s color separately from its text color. The property even has better-than-expected browser support — it works in Firefox and prefixed in Safari. Here’s the catch: If you’re not clearing descenders, Safari puts the line on top of the text. 🙃

Firefox:

Safari:

text-decoration-skip

text-decoration-skip toggles skipping descenders in underlined text.

This property is non-standard and works only in Safari right now, so you need the -webkit- prefix to use it. Safari enables this property by default though, which is why underlines skip descenders even on websites that don’t specify it.

If you’re using Normalize, know that recent versions disable the property to keep things consistent between browsers. You need to flip it back on if you want those dreamy underlines.

text-decoration-style

text-decoration-style offers the same sorts of lines you’d expect from border-style, but adds in wavy lines too.

Here are the different values you can use:

  • dashed
  • dotted
  • double
  • solid
  • wavy

Right now, text-decoration-style works only in Firefox, so here’s a screenshot:

An assortment of solid-color underline styles

Look familiar?

What’s missing?

The text-decoration-* properties are far more intuitive than using other CSS properties to style underlines. But if we take another look at our earlier requirements, these properties don’t offer a way to specify line thickness or position.

After doing a little research, I came across these two properties:

  • text-underline-width
  • text-underline-position

It looks like they were pitched in earlier drafts of CSS, but never implemented due to lack of interest. Hey, don’t blame me.

Takeaways

So what’s the best way to underline text?

It depends.

For small text, I recommend using text-decoration and then optimistically applying text-decoration-skip on top. It looks a little bland in most browsers, but underlines have looked that way forever and people don’t seem to mind. Plus there’s always the chance that if you’re patient enough, all your underlines will look awesome later on without you having to change a thing.

For body text, probably use the background-image approach. It works, it looks great, and there are Sass mixins for it. You can probably omit text-shadow it if the underline is thin or in a different color from the text.

For single lines of text, use border-bottom and whatever other properties you want to go with it.

And for skipping descenders on top of a gradient or background image, try using SVG filters. Or just avoid using an underline altogether.

In the future when browser support is better, the answer is text-decoration-* all the way.


Also see Benjamin Woodruff’s post CSS Underlines Suck, which coincidentally treads this ground in a similar way.


Styling Underlines on the Web originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/styling-underlines-web/feed/ 17 245767