Thomas Yip – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Sun, 03 Mar 2019 21:29:56 +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 Thomas Yip – CSS-Tricks https://css-tricks.com 32 32 45537868 The “C” in CSS: The Cascade https://css-tricks.com/the-c-in-css-the-cascade/ https://css-tricks.com/the-c-in-css-the-cascade/#comments Tue, 13 Nov 2018 15:01:24 +0000 http://css-tricks.com/?p=278596 Following up from Geoff’s intro article on The Second “S” in CSS, let’s now move the spotlight to the “C” in CSS — what we call the Cascade. It’s where things start to get messy, and even confusing …


The “C” in CSS: The Cascade originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Following up from Geoff’s intro article on The Second “S” in CSS, let’s now move the spotlight to the “C” in CSS — what we call the Cascade. It’s where things start to get messy, and even confusing at times.

Have you ever written a CSS property and the value doesn’t seem to work? Maybe you had to turn to using !important to get it going. Or perhaps you resorted to writing the CSS inline on the element in the HTML file.

<div style="background:orange; height:100px; width:100px;">
  Ack, inline!
</div>

Speaking of inline styles, have you wondered why SVG editors use them instead of a separate CSS file? That seems kinda weird, right?

<svg id="icon-logo-star" viewBox="0 0 362.62 388.52" width="100%" height="100%">
  <style>
    .logo {
      fill: #ff9800;
    }
  </style>
  <title>CSS Tricks Logo</title>
  <path class="logo" d="M156.58 239l-88.3 64.75c-10.59 7.06-18.84 11.77-29.43 11.77-21.19 0-38.85-18.84-38.85-40 0-17.69 14.13-30.64 27.08-36.52l103.6-44.74-103.6-45.92C13 142.46 0 129.51 0 111.85 0 90.66 18.84 73 40 73c10.6 0 17.66 3.53 28.25 11.77l88.3 64.75-11.74-104.78C141.28 20 157.76 0 181.31 0s40 18.84 36.5 43.56L206 149.52l88.3-64.75C304.93 76.53 313.17 73 323.77 73a39.2 39.2 0 0 1 38.85 38.85c0 18.84-12.95 30.61-27.08 36.5l-103.61 45.91L335.54 239c14.13 5.88 27.08 18.83 27.08 37.67 0 21.19-18.84 38.85-40 38.85-9.42 0-17.66-4.71-28.26-11.77L206 239l11.77 104.78c3.53 24.72-12.95 44.74-36.5 44.74s-40-18.84-36.5-43.56z"></path>
</svg>

Well, the cascade has a lot to do with this. Read on to find out how styling methods affect what’s being applied to your elements and how to use the cascade to your advantage because, believe me, it’s a wonderful thing when you get the hang of it.

TL;DR: Jump right to the CSS order diagram for a visual of how everything works.

The cascade cares about how and where styles are written

There are a myriad of ways you can apply CSS rules to an element. Below is an example of how stroke: red; can be applied to the same element. The examples are ordered in ascending priority, where the highest priority is at the bottom:

<!-- Inheritance -->
<g style="stroke: red">
  <rect x="1" y="1" width="10" height="10" /> <!-- inherits stroke: red -->
</g>

<!-- Inline attributes -->
<rect x="1" y="1" width="10" height="10" stroke="red" />

<!-- External style sheet -->
<link rel="stylesheet" href="/path/to/stylesheet.css">

<!-- Embedded styles -->
<style>
  rect { stroke: red; }
</style>

<!-- Different specificity or selectors -->
rect { stroke: red; }
.myClass { stroke: red; }
#myID { stroke: red; }

<!-- Inline style -->
<g style="stroke: red"></g>

<!-- Important keyword -->
<g style="stroke: red !important"></g>

Inheritance? Embedded? External? Inline? Specificity? Important? Yeah, lots of terms being thrown around. Let’s break those down a bit because each one determines what the browser ends up using when a web page loads.

Elements can inherit styles from other elements

Both HTML and SVG elements can inherit CSS rules that are applied to other elements. We call this a parent-child relationship, where the element the CSS is applied to is the parent and the element contained inside the parent is the child.

<div class="parent">
  <div class="child">I'm the child because the parent is wrapped around me.</div>
</div>

If we set the text color of the parent and do not declare a text color on the child, then the child will look up to the parent to know what color its text should be. We call that inheritance and it’s a prime example of how a style cascades down to an element it matches… or “bubbles up” the chain to the next matched style.

However, inheritance has the lowest priority among styling methods. In other words, if a child has a rule that is specific to it, then the inherited value will be ignored, even though the inherited value may have an important keyword. The following is an example:

<div class="parent" style="color: red !important;">
  <div class="child">I'm the child because the parent is wrapped around me.</div>
</div>

See the Pen Child ignores inline inheritance with !important by Geoff Graham (@geoffgraham) on CodePen.

SVG inline attributes

For SVG elements, we can also apply styles using inline attributes, where those have the second lowest priority in the cascade. This means the CSS rules in a stylesheet will be able to override them.

<rect x="1" y="1" width="10" height="10" stroke="red" />
rect {
  stroke: blue;
}

See the Pen Stylesheet overrides SVG inline attributes by Geoff Graham (@geoffgraham) on CodePen.

Most SVG editors use inline attributes for portability; that is, the ability to copy some elements and paste them elsewhere without losing the attributes. Users can then use the resultant SVG and style its elements using an external stylesheet.

Stylesheets

Stylesheets are divided into two flavors: external and embedded:

<!-- External style sheet -->
<link rel="stylesheet" href="/path/to/stylesheet.css">

<!-- Embedded styles -->
<style>
  div { border: 1px solid red }
</style>

Embedded styles have the same priority as external stylesheets. Therefore, if you have the same CSS rules, ordering rules applies.

See the Pen Embedded styles override stylesheet rules by Geoff Graham (@geoffgraham) on CodePen.

All stylesheets follow ordering rules, where files that are defined later, will have higher priority than those defined earlier. In this example, stylesheet-2.css will take precedence over the stylesheet-1.css file because it is defined last.

<link rel="stylesheet" href="/path/to/stylesheet-1.css">
<link rel="stylesheet" href="/path/to/stylesheet-2.css">

Specificity or selectors

How you select your elements will also determine which rules are applied, whereby tags (e.g. <p>, <div>), classes (e.g. .my-class) and IDs (e.g. #myI-id) have ascending priorities.

See the Pen Specificity by selectors by Geoff Graham (@geoffgraham) on CodePen.

In the example above, if you have a div element with both .my-class and #my-id, the border will be red because IDs have higher priority than classes and tags.

*Specificity has higher priority than ordering rules, therefore, irrespective if your rule is at the top or bottom. Specificity still has higher priority and will be applied.

Ordering

CSS rules always prioritize from left-to-right, then from top-to-bottom.

<!-- Blue will be applied because it is on the right -->
<div style="border: 1px solid red; border: 1px solid blue;"></div> 

<style>
  div {
    border: 1px solid red;
    border: 1px solid blue; /* This will be applied because it is at the bottom */
  }
</style>

Inline styles

Inline styles have the second highest priority, just below the !important keyword. This means that inline styles are only overridden by the important keyword and nothing else. Within inline styles, normal ordering rules applies, from left-to-right and top-to-bottom.

<div style="1px solid red;"></div>

The important keyword

Speaking of the !important keyword, it is used to override ordering, specificity and inline rules. In other words, it wields incredible powers.

Overriding inline rules

<style>
  div {
    /* This beats inline styling */
    border: 1px solid orange !important;
    /* These do not */
    height: 200px;
    width: 200px;
  }
</style>

<div style="border: 1px solid red; height: 100px; width: 100px;"></div>

In the example above, without the important keyword, the div would have a red border because inline styling has higher priority than embedded styles. But, with the important keyword, the div border becomes orange, because the important keyword has higher priority than inline styling.

Using !important can be super useful, but should be used with caution. Chris has some thoughts on situations where it makes sense to use it.

Overriding specificity rules

Without the important keyword, this div border will be blue, because classes have higher priority than tags in specificity.

<style>
  /* Classes have higher priority than tags */
  .my-class {
    border: 1px solid blue;
    height: 100px;
    width: 100px;
  }
  
  div { 
    border: 1px solid red;
    height: 200px;
    width: 200px;
  }
</style>

<div class="my-class"></div>

See the Pen Classes beat tags by Geoff Graham (@geoffgraham) on CodePen.

But! Adding the important keyword to the tag rules tells the element to ignore the cascade and take precedence over the class rules.

<style>
  .my-class { border: 1px solid red; }
  
  /* The important keyword overrides specificity priority */
  .my-class { border: 1px solid blue !important; }
</style>

<div class="my-class"></div>

See the Pen !important ignores the cascade by Geoff Graham (@geoffgraham) on CodePen.

Overriding ordering rules

OK, so we’ve already talked about how the order of rules affects specificity: bottom beats top and right beats left. The surefire way to override that is to put !important into use once again.

In this example, the div will take the red border, even though the blue border is the bottom rule. You can thank !important for that handiwork.

<style>
  div { border: 1px solid red !important; } /* This wins, despite the ordering */
  div { border: 1px solid blue; }
</style>

<div></div>

See the Pen Important wins over ordering by Geoff Graham (@geoffgraham) on CodePen.

Visualizing the cascade

Who knew there was so much meaning in the “C” of CSS? We covered a ton of ground here and hopefully it helps clarify the way styles are affected and applied by how we write them. The cascade is a powerful feature. There are opinions galore about how to use it properly, but you can see the various ways properties are passed and inherited by elements.

More of a visual learner? Here’s a chart that pulls it all together.

Download chart

The “C” in CSS: The Cascade originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/the-c-in-css-the-cascade/feed/ 8 278596
Using Custom Fonts With SVG in an Image Tag https://css-tricks.com/using-custom-fonts-with-svg-in-an-image-tag/ https://css-tricks.com/using-custom-fonts-with-svg-in-an-image-tag/#comments Thu, 21 Jun 2018 14:11:18 +0000 http://css-tricks.com/?p=272772 When we produce a PNG image, we use an <img> tag or a CSS background, and that’s about it. It is dead simple and guaranteed to work.

PNG is way simpler to use in HTML than SVG

Unfortunately, the same …


Using Custom Fonts With SVG in an Image Tag originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
When we produce a PNG image, we use an <img> tag or a CSS background, and that’s about it. It is dead simple and guaranteed to work.

PNG is way simpler to use in HTML than SVG

Unfortunately, the same cannot be said for SVG, despite its many advantages. Although you’re spoiled for choices when using SVG in HTML, it really boils down to inline, <object> and <img>, all with serious gotchas and trade-offs.

Problems with inline SVG

If you’re inlining SVG, you lose the ability to use browser cache, Gzip compression between servers and browsers, and search engine image indexing (inline SVG is not considered as an image). Even though your image may not have changed one bit, they are always reloaded and this causes slower loading times for your website, a trade-off that most are not willing to tolerate.

In addition, inlining SVG also causes complex dependency problems where you cannot easily insert images into HTML and have to resort to scripts (PHP or otherwise). When you have more than a few images, this becomes a huge problem when it comes to maintaining your site, because essentially you can’t use the <img> tag anymore.

No doubt, there are areas where inlining SVG shines — that is, if you want your images to display quickly, without waiting for other resources to load. Apart from that, clearly, you just can’t inline everything.

Problems with object tag

SVG is well known for its excellent quality when displayed on devices of all resolutions and its ability to refer to external resources — like CSS and fonts — while keeping the file size very small. The idea is to have many SVGs that all share a single CSS or a single font file, to reduce the amount of resources you have to download.

The myth of resource sharing

Unknown to many, sharing external resources for SVG only applies to inline SVG. Because usage of <object> tags allow access to these resources, the perception is that the browser will download a single copy of your CSS, even though you have many <object> tags referring to the same CSS file.

This however, is not true at all:

Multiple object tags will download multiple CSS

Compounding the problem is the fact that <object> tags are not recognized as an image, and therefore image search indexing is not possible.

Further compounding the problem are dependency issues. For example, let’s say you have 100 images, and 25 of them use a Roboto font, another 25 use Lato, 25 use Open Sans, while the rest use a combination of the three fonts. Your CSS would need to refer to all three fonts because it is quite impossible to keep track of which file is using which fonts, meaning you may be loading fonts you may not require on certain pages.

The image tag

That leaves us with the <img> tag, which has a lot going for it. Because it’s the same tag used for other image formats, you get familiarity, browser caching, Gzip compression and image search. Each image is self-contained, with no dependency issues.

SVG losing fonts if used with the <img> tag

The only problem is you will lose your fonts. To be more precise, if you have any text in your SVG, unless you embed fonts, your text will be displayed with system fonts, typically Times New Roman. You’ve spent hours selecting a beautiful font but the moment you use the <img> tag to embed SVG, all that is lost. How can this be acceptable?

Investigating font rasterization

Converting fonts into paths

Our first reaction is to see if we can perform font rasterization. It is a commonly used technique to convert fonts into paths, so it’ll render well on all devices and maintain zero dependencies. On the surface, this works very well, and on the editor, everything looks perfect.

Although the rasterized SVG came in at a whopping 137 KB compared to 15.7 KB before rasterization, we were optimistic because, after optimizing our SVG using Gzip compression, the rasterized file is reduced to 11 KB, slightly smaller than the equivalent PNG at 11.9 KB.

Original Font rasterization Font rasterization (.svgz)
15.7 KB 137 KB 11.0 KB
PNG @ 1x PNG @ 2x PNG @ 3x
11.9 KB 26.5 KB 42.6 KB
SVG image with font rasterization

Alas, once we embed the rasterized SVG into HTML, we found our optimism to be premature. Although it might look great on high-resolution displays, the quality on low-resolution displays is unacceptable.

Rasterized fonts on top and original at the bottom

The bottom of the image is the original, with clearly displayed fonts while, on top, fonts are pixelated with font rasterization.

Cleartype difference when shown on screens

What’s happening is that most operating systems will optimize fonts to ensure they are shown clearly and sharp on all screens. On Windows, this is called ClearType, and since we rasterized our fonts, no optimizations will be applied, resulting in blurred text, particularly visible on low-resolution screens.

Obviously, a reduction in quality is unacceptable, so back to the drawing board.

Font embedding to the rescue

Initially, we were extremely skeptical about font embedding, mainly because of the complicated workflow.

To embed fonts in SVG, you first have to know what font families are used. Then you need to find these font files and download them. Once downloaded, you have to convert regular, bold, italics and bold italics to Base64 encoding. If you’re doing it manually, it is quite impossible, over a large number of files, to know which file uses bold and which ones does not. Then you have to copy all four Base64 encoded strings into your SVG.

Surely, there has to be a better way. And that’s why we built Nano. Nano scans SVG automatically and inserts only the fonts that are used. For example, if bold is not used or if no text exists, then no fonts will be embedded.

Still, the resulting file is huge and is not competitive with the PNG equivalent, so we plugged away and built our own SVG optimizer (Nano) that will reduce SVG file sizes to a trickle. (See how Nano compresses SVG.) In addition, we also optimized how we embed fonts into SVG, resulting in very small file sizes.

SVG image with text, optimized with Nano and fonts embedded

Comparing file sizes and bandwidth savings

Original Font rasterization Unoptimized font embedding Nano font embedding
Size 15.7 KB 137 KB 65.2 KB 22.0 KB
Gzip 3.57 KB 11.0 KB 44.5 KB 11.7 KB
PNG @ 1x PNG @ 2x PNG @ 3x
Size 11.9 KB 26.5 KB 42.6 KB
Gzip 12.1 KB 26.1 KB 41.7 KB

From the above, we can see that Nano produces an SVG that is extremely lightweight even with embedded fonts, coming in at 11.7 KB (Gzipped) compared with the equivalent PNG @1x at 11.9 KB. While this may seem insignificant, the total bandwidth saved on your site will surely be significant.

Let’s assume that 50% of your traffic is low resolution, 40% is 2X resolution and the remaining 10% is 3X resolution. If your website has 10,000 hits on a single image:

(5,000 * 11.9 KB) + (4,000 * 26.5 KB) + (1,000 * 42.6 KB) = 208.1 MB

If you use Nano, compressed SVG with GZip:

10,000 * 11.7 KB = 117.0 MB

This will result in: 208.1 MB – 117.0 MB = 91.1 MB savings, or 43.7%, bandwidth savings, a significant amount by any measure.

In addition to the bandwidth savings, you get a far simpler workflow without resorting to multiple PNG images with multiple srcset, with much better quality, including operating system font enhancement to ensure your images stay crisp and sharp on devices of all resolutions. Best of all, better user experience for your users, since your site will load faster — especially so on devices with high resolution.

Thoroughly testing Nano

Not satisfied with all the savings, we began to look for SVG images to thoroughly test Nano. A total 2,571 SVG files of various sizes and designs were used, totaling up 16.3 MB. And after Nano optimization, resulting in 6.2 MB, an astonishing 61.8% savings in size.

A small selection of over 2500 SVG images used to test Nano

Showing a visual difference

Because of the sheer number of files that we were testing, and it increases from time to time, we have to build an automated test, including automatically highlighting pixel differences before and after optimization. One of the complaints on other SVG optimizers is the fact that minifying SVG may break your image, causing it to render differently compared to the original.

To this end, we carry over the pixel differentiation in our automated test into Nano itself. That is, Nano will warn you if it detects that the SVG it optimizes has a pixel difference of more than 1% when compared to the original, therefore ensuring Nano’s optimization will never break an SVG.

Nano optimization showing visual difference

Because fonts are embedded and preserved, plus SVG being a vector graphics format, rendering quality on all resolution is incomparable to other raster formats.

What’s next?

We hope our work will make SVG easier to use everywhere. We’re now working on producing even smaller file sizes, porting our codes to work on Node.js so you can automate your production builds with Nano, among others.

Do you think you’ll find Nano helpful in your projects? Let me know in the comments!


Using Custom Fonts With SVG in an Image Tag originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/using-custom-fonts-with-svg-in-an-image-tag/feed/ 18 272772