Archiwum kategorii: CSS

Changing Emoji Skin Tones Programmatically

Post pobrano z: Changing Emoji Skin Tones Programmatically

So, you know how many emoji have different skin tones? Emoji skin tones are extremely popular, especially over text and on social media. The raised black fist emoji (✊🏿) was voted “The Most 2020 Emoji” by Emojipedia’s World Emoji Awards.

Each tone is a modifier and many emoji are made up of modifiers and base encodings that map to specific characters. Unfortunately, not every emoji library supports modifiers. But, given their popularity, emoji skin tone modifiers are more than a “nice to have” feature. Plus, they’re a smart way to work because they allow us to write more modular and efficient code.

So that’s what we’re doing in this article: figure out how to work with emoji modifiers programmatically. This way, if you’re ever stuck without skin tone support — or want to create custom variations of other emoji — then you’ll know how!

Meet the Fitzpatrick scale

Skin tone modifiers were officially added to emoji in 2015 as part of Unicode 8.0. They are based on the Fitzpatrick scale, which is a formal classification of human skin tones. The following chart shows how the emoji characters match to Fitzpatrick types:

Skin tone character Fitzpatrick type
🏻 1-2
🏼 3
🏽 4
🏾 5
🏿 6

In the simplest use case, when one of these characters is appended to an emoji that supports skin tone modifiers, it will change the skin tone of the emoji.

Another way to say that: 👶 +🏽 = 👶🏽

Applying skin tone modifiers with CSS

To swap between emoji skin tones using CSS, we would start with the base emoji character (👶) and then append the skin tone using the ::after pseudo-selector.

CodePen Embed Fallback

In addition to using the rendered emoji characters, we could use the Unicode hex codes instead:

CodePen Embed Fallback

Removing and swapping skin tone modifiers with JavaScript

What if the emoji you’re working with has already had a skin tone modifier applied? For that, we’ll need to move beyond CSS. Here’s an example using JavaScript:

CodePen Embed Fallback

What’s going on here? First, we start with a baby emoji with Fitzpatrick Type 4. We then pass it into the function removeModifier, which searches for any of the skin tone modifiers and removes it from the string. Now that we have the emoji without a modifier, we can add whichever modifier we like.

While this approach works with many emoji, we run into problems when other modifiers are introduced. That’s why we now need to talk about…

Working with ZWJ sequences

Zero width joiner (ZWJ) sequences are like the compound words of Unicode. They consist of two or more emoji joined by the zero width joiner, U+200D.

ZWJ sequences are most commonly used to add gender modifiers to emoji. For example, a person lifting weights, plus ZWJ, plus the female sign, equals a woman lifting weights (️🏋️ + ♀︎ = 🏋️‍♀️).

There’s a few important things to need to keep in mind when working with ZWJ sequences:

  • The sequences are only recommendations. They come from the Unicode Consortium and are not guaranteed to be supported on every platform. If they are not supported by a platform, then a fallback sequence of regular emoji will be displayed instead.
  • Skin tone modifiers, if present, must be included after the emoji but before the ZWJ.
  • Some ZWJ sequences include multiple emoji that each have different skin tone modifiers.

Given this information, we need to make the following changes to the previous code example:

  • The skin tone modifiers need to be inserted immediately after any base emoji rather than simply being appended to the end of the emoji.
  • If there are multiple emoji in a ZWJ sequence that have skin tone modifiers, then the modifiers will need to be replaced for each of those emoji.
CodePen Embed Fallback


From this example, you may notice the limitation of consistency. The editor view shows each of the characters in a ZWJ sequence separately, with exception to the skin tone modifiers, which are immediately applied to their corresponding emoji. The console or results views, on the other hand, will attempt render the character for the entire sequence.

Support for this will vary by platform. Some editors may attempt to render ZWJ sequences, and not all browsers will support the same sets of ZWJ sequences.

Additionally, adding skin tones in a ZWJ sequence requires knowing what’s being used as the base emoji. While this would be relatively simple in a situation where the emoji are provided by a known collection, things become more difficult if we want to be able to handle arbitrary input from a user.

Also, be aware that the CSS solutions in this post are not compatible with ZWJ sequences.

Questions to guide development

I put some questions together you may want to ask yourself when you’re designing a system that needs to handle emoji skin tone modifiers:

  • Do I have control over which emoji my system will interact with?
  • Does my emoji library have information about which emoji support skin tone modifiers?
  • Does my system need to add, remove, or change the modifiers?
  • Does my platform support ZWJ sequences? If so, which ones?
  • Does my system need to support ZWJ sequences with multiple skin tone modifiers?

Hopefully, between the answers to these questions and the examples we’ve looked at here, you’ll have everything you need to support emoji skin tone modifiers in situations where you need them.

The post Changing Emoji Skin Tones Programmatically appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Weaved Webs

Post pobrano z: Weaved Webs

There is a bit of an irony with Jamstack.

The concept is simple: you put pre-rendered, static files on web hosting (a CDN) designed to do that well. That’s it. If you need to do more, anything you do from there is done with client-side JavaScript, which is likely talking to serverless functions because that’s the spiritual partner to Jamstack on the back end. I heard Guillermo Rauch say at Smashing Conf the other day that it isn’t exactly a “stack” in that it’s almost entirely non-prescriptive in what you do. While I like the word Jamstack, that also feels fair.

The irony is that while the concept is simple, that simplicity can be the cause of complexity.

Netlify, the company largely behind Jamstack, knows this. They know that without a back-end server with back-end languages, something like a basic contact form gets complicated. Instead of being in no-brainer solved-problem territory, we have to figure out another way to process that form. So, they solve that problem for you (among others, like auth and serverless functions). But there are tons of other companies that want to be that cog in your machine.

That’s just one potential complication. What do you use for a CMS or other data storage? What is your build process like? How do you see previews of content changes? How do you do auth? What if you need some fancy calendar widget? What if you want to sell something? Anything a website can do, Jamstack has an answer for — it’s just that combining all those answers can feel disjointed and potentially confusing.

Dave recently played with Eleventy + Tailwind + Netlify CMS (which is Jamstack-y) and said it felt like cattle herding:

So my little mashup, which was supposed to be just 3 technologies ended up exposing me to ~20 different technologies and had me digging into nth-level dependency source code after midnight. If there’s an allegory for what I don’t like about modern-day web development, this is it. You want to use three tools, but you have to know how to use twenty tools instead. If modules and components are like LEGO, then this is dumping out the entire bin on the floor just to find one tiny piece you need.

“The tangled webs we weave,” indeed.

In a conversation between Richard MacManus and Matt Mullenweg¹, Richard quotes Matt:

You can patch together a dozen services, each with its own account and billing, for hundreds of dollars a month, to get a similar result you’d have for a few dollars a month using WordPress on shared hosting,” he said. “And it would be more fragile, because the chain is only as strong as its weakest link. You are chaining together different toolsets, logins, billing, hosting… any part of it going down can break the entire flow.

If I was considering Jamstack for a particular project, and the grand total really was twelve services, I probably would reconsider, particularly if I could reach for a tool like WordPress and bring it down to one. There are plenty of other fair criticisms of Jamstack, particularly since it is early-days. The story of “CMS with Preview” isn’t particularly great, for example, which is a feature you don’t even think about with WordPress because, duh, obviously it has that.

And Jamstack can do some things that are very ahead of the game that I cherish. Git-based deployment? All websites should have that. Previews of my pull requests? Hot damn. Sub -100-millisecond first requests? Yes please. Not having to diddle with cache? Sweet. Catch up, other stacks.

I’m saying there are baby bear choices to be made here. You get there by doing what you’re probably already doing anyway: putting your adult pants on, thinking about what your project needs, and choosing the best option.

I have production WordPress sites. Like this one! It’s great!

I have production Jamstack sites. Like this one! It’s not a complicated web of services. It’s a static site generator with content in the GitHub repo deployed with Netlify. While CSS-Tricks can do about 100 things that this site can’t, it has a few tricks up its sleeve that CSS-Tricks can’t do, like accept pull requests on content.

I feel like I’ve chosen pretty well in all my cases.

  1. While Matt is clearly incentivized to defend the WordPress approach, it feels to me the opinions here are genuine; in part because Automattic invests in alternative stack approaches, and that WordPress and Jamstack are not mutually exclusive. I enjoyed responses to this, like Ohad Eder-Pressman’s open letter, which is also full of incentivized-but-genuine thoughts.

The post Weaved Webs appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Enforcing performance budgets with webpack

Post pobrano z: Enforcing performance budgets with webpack

As you probably know, a single monolithic JavaScript bundle — once a best practice — is no longer the way to go for modern web applications. Research has shown that larger bundles increase memory usage and CPU costs, especially on mid-range and low-end mobile devices.

webpack has a lot of features to help you achieve smaller bundles and control the loading priority of resources. The most compelling of them is code splitting, which provides a way to split your code into various bundles that can then be loaded on demand or in parallel. Another one is performance hints which indicates when emitted bundle sizes cross a specified threshold at build time so that you can make optimizations or remove unnecessary code.

The default behavior for production builds in webpack is to show a warning when an asset size or entry point is over 250KB (244KiB) in size, but you can configure how performance hints are shown and size thresholds through the performance object in your webpack.config.js file.

Production builds will emit a warning by default for assets over 250KB in size

We will walk through this feature and how to leverage it as a first line of defense against performance regressions.

First, we need to set a custom budget

The default size threshold for assets and entry points (where webpack looks to start building the bundle) may not always fit your requirements, but they can be configured to.

For example, my blog is pretty minimal and my budget size is a modest 50KB (48.8KiB) for both assets and entry points. Here’s the relevant setting in my webpack.config.js:

module.exports = {
  performance: {
    maxAssetSize: 50000,
    maxEntrypointSize: 50000,

The maxAssetSize and maxEntrypointSize properties control the threshold sizes for assets and entry points, respectively, and they are both set in bytes. The latter ensures that bundles created from the files listed in the entry object (usually JavaScript or Sass files) do not exceed the specified threshold while the former enforces the same restrictions on other assets emitted by webpack (e.g. images, fonts, etc.).

Let’s show an error if thresholds are exceeded

webpack’s default warning emits when budget thresholds are exceeded. It’s good enough for development environments but insufficient when building for production. We can trigger an error instead by adding the hints property to the performance object and setting it to 'error':

module.exports = {
  performance: {
    maxAssetSize: 50000,
    maxEntrypointSize: 50000,
    hints: 'error',
An error is now displayed instead of a warning

There are other valid values for the hints property, including 'warning' and false, where false completely disables warnings, even when the specified limits are encroached. I wouldn’t recommend using false in production mode.

We can exclude certain assets from the budget

webpack enforces size thresholds for every type of asset that it emits. This isn’t always a good thing because an error will be thrown if any of the emitted assets go above the specified limit. For example, if we set webpack to process images, we’ll get an error if just one of them crosses the threshold.

webpack’s performance budgets and asset size limit errors also apply to images

The assetFilter property can be used to control the files used to calculate performance hints:

module.exports = {
  performance: {
    maxAssetSize: 50000,
    maxEntrypointSize: 50000,
    hints: 'error',
    assetFilter: function(assetFilename) {
      return !assetFilename.endsWith('.jpg');

This tells webpack to exclude any file that ends with a .jpg extension when it runs the calculations for performance hints. It’s capable of more complex logic to meet all kinds of conditions for environments, file types, and other resources.

The build is now successful but you may need to look for a different way to control your image sizes.


While this has been a good working solution for me, a limitation that I’ve come across is that the same budget thresholds are applied to all assets and entry points. In other words, it isn’t yet possible to set multiple budgets as needed, such as different limits for JavaScript, CSS, and image files.

That said, there is an open pull request that should remove this limitation but it is not merged yet. Definitely something to keep an eye on.


It’s so useful to set a performance budget and enforcing one with webpack is something worth considering at the start of any project. It will draw attention to the size of your dependencies and encourage you to look for lighter alternatives where possible to avoid exceeding the budget.

That said, performance budgeting does not end here! Asset size is just one thing of many that affect performance, so there’s still more work to be done to ensure you are delivering an optimal experience. Running a Lighthouse test is a great first step to learn about other metrics you can use as well as suggestions for improvements.

Thanks for reading, and happy coding!

The post Enforcing performance budgets with webpack appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Optimizing CSS for faster page loads

Post pobrano z: Optimizing CSS for faster page loads

A straightforward post with some perf data from Tomas Pustelnik. It’s a good reminder that CSS is a crucial part of thinking web performance, and for a huge reason:

Any time [the browser] encounters any external resource (CSS, JS, images, etc.) it will assign it a download priority and initiate its download. Priorities are important because some resources are critical to render a page (eg. main stylesheet and JS files) while others may be less important (like images or stylesheets for other media types).

In the case of CSS, this priority is usually high because stylesheets are necessary to create CSSOM (CSS Object Model). To render a webpage browser has to construct both DOM and CSSOM.

That’s why CSS is often referred to as a “blocking” resource. That’s desirable to some degree: we wouldn’t want to see flash-of-unstyled-websites. But we get real perf gains when we make CSS smaller because it’s quicker to download, parse, and apply.

Aside from the techniques in the post, I’m sure advocates of atomic/all-utility CSS would love it pointed out that the stylesheets from those approaches are generally way smaller, and thus more performant. CSS-in-JS approaches will sometimes bundle styles into scripts so, to be fair, you get a little perf gain at the top by not loading the CSS there, but a perf loss from increasing the JavaScript bundle size in the process. (I haven’t seen a study with a fair comparison though, so I don’t know if it’s a wash or what.)

Direct Link to ArticlePermalink

The post Optimizing CSS for faster page loads appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Modifying Specific Letters with CSS and JavaScript

Post pobrano z: Modifying Specific Letters with CSS and JavaScript

Changing specific characters can be a challenge in CSS. Often, we’re forced to implement our desired changes one-by-one in HTML, perhaps using the span element. But, in a few specific cases, a CSS-focused solution may still be possible. In this article, we’ll start by looking at some CSS-first approaches to changing characters, before considering a scenario where we need to turn to JavaScript.


Right now, CSS doesn’t excel at targeting specific characters without making alterations to the HTML. However, there are a few scenarios where CSS could be the go-to.


The @font-face rule is regularly used to create custom fonts, but its unicode-range property can also allow us to target specific characters. 

For example, imagine our site often contains ampersands in its headings. Instead of using the heading font, we want something a tad more flamboyant. We can look up the unicode value of an ampersand (U+0026) and use unicode-range to target this specific character.

@import url('');

h1, h2, h3, h4, h5, h6 {
  font-family:  'Ampersand', Montserrat, sans-serif;

@font-face {
  font-family: 'Ampersand';
  src: local('Times New Roman');
  unicode-range: U+0026;

Try this with the following HTML to see it in action:

<h1>Jane Austen Novels</h1>
<h2>Pride & Prejudice</h2>
<h2>Sense & Sensibility</h2>


The ::first-letter pseudo-element was primarily designed with drop caps in mind and it is supported by all major browsers.

p::first-letter {
  font-size: 125%;
  font-weight: bold;

Of course, this is only useful in a relatively limited number of scenarios. There have been several calls for an  ::nth-letter pseudo-element (including here on CSS-Tricks) but, right now, that’s just a pipe dream!


Using the ::after pseudo-element and content property, we can achieve a similar effect for the final character — so long as that character is always the same. For example, here’s how we could add a jazzy, italicized exclamation point after every h2 element:

h2::after {
  content: '\0021';
  color: red;
  font-style: italic;


Finally, there’s the font-variant-alternates property. This is only supported by Firefox, so it’s not recommended for production, but it may be worth knowing about for really specific scenarios: if a font happens to contain alternate glyphs, we can use this property with the character-variant() function to select a preferred glyph for a character of our choice.


Turning to JavaScript doesn’t need to come at a cost to performance, especially if we run HTML-altering functions at build time. The most common use case is probably to find and replace specific characters in our HTML with a span element. For simplicity’s sake, I’ll begin with an example on the client-side, and after that we’ll look into running this at build with webpack.

Find and replace at runtime

Let’s imagine that, whenever we have the text “LOGO” in a header on our site, we want to add a special style to the first “O” character only, by wrapping it in a span element with the class .special-o.

const headings = document.querySelectorAll("h1, h2, h3, h4, h5, h6");

for (const heading of headings) {
  heading.innerHTML = heading.innerHTML
    .replace(/\bLOGO\b/g, 'L<span class="special-o">O</span>GO');

In the JavaScript above, we’re performing a find-and-replace on every heading tag. 

Our regular expression uses the metacharacter \b to ensure that LOGO is always a word — rather than an element of a larger word. For example, we don’t want to match the plural  “LOGOS.” Right now, it would be impossible to do this with CSS, not least because we only want to target the first “O” in the sequence.

The same principle applies if we want to replace the “O” — or even the whole word “LOGO” — with an image. 

Find and replace at build

There are plenty of build tools out there, but as webpack is so popular, we’ll use that for our example — and luckily, there’s a plugin for what we need called string-replace-loader. For those new to webpack, a loader is used to preprocess files. Here, we can perform a find-and-replace on specific files as part of our build. 

First, we need to install the plugin:

npm install --save-dev string-replace-loader

Then, inside webpack.config.js add:

module.exports = {
  // ...
  module: {
    rules: [
        test: /\.html$/i,
        loader: 'string-replace-loader',
        options: {
          search: '/\bLOGO\b/g',
          replace: 'L<span class="special-o">O</span>GO',

By changing the test property value, we could target JSX, TSX, PUG, Handlebars or any other templating file format:

/\.html$/i # HTML
/\.[jt]sx$/i # JSX or TSX
/\.pug$/i # PUG
/\.handlebars$/i # Handlebars

The advantage of this approach is that no unnecessary JavaScript will run in our client’s browser. 

Final note

Finally, if you’re comfortable creating and editing fonts and would rather avoid CSS or JavaScript, a custom font could be a solution for many of the scenarios set out above. There are plenty of free font-editing tools such as Font Forge or Birdfont for those who want to try this more design-focused approach.

The post Modifying Specific Letters with CSS and JavaScript appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Setting up and Customizing the Ant Design System in a Nuxt App

Post pobrano z: Setting up and Customizing the Ant Design System in a Nuxt App

I don’t typically work with UI libraries because they can be cumbersome and hard to override, which can contribute to a bloated. However, Ant Design has recently gained some some of my affection because it’s easy to use, has extensible defaults, and features a delicate design.

Nuxt and Ant Design work well together, in part because of Nuxt’s code-splitting and tree-shaking abilities, not to mention Nuxt’s new static target deployment option. I can serve an app using Ant Design with great performance scores.

Combining the two was a little tricky and there isn’t a lot in the way of documentation for how to do it, so what follows are the steps you need to set it up. Let’s get started!


The first step is installing the ant-design-vue package, along with Less.js and less-loader, which we will need to create our Less variables:

yarn add ant-design-vue less less-loader
# or
npm i ant-design-vue less less-loader

Now lets tell Nuxt to use it globally via a plugin. We’ll create a file called antd-ui.js:

import Vue from 'vue'
import Antd from 'ant-design-vue/lib'


You may notice that unlike the process outlined in the Ant Design getting started guide, we are not importing the global CSS file they mention. That’s because we’re going to manually import the base variable Less file instead so that we can override it. 

We have a few things to do in our nuxt.config.js file. First, let’s register the plugin we just made:

plugins: ["@/plugins/antd-ui"],

Next, we’re going to let webpack know we’d like to build Less:

build: {
   loaders: {
     less: {
       lessOptions: {
         javascriptEnabled: true,

Finally, we need to create a global stylesheet for our variables that imports Ant Design’s defaults as well as our overrides:

css: [

We can see that this file exists in a /assets folder, so let’s make it. We’ll create a file in there called variables.less, and import Ant Design’s Less variables:

@import '~ant-design-vue/dist/antd.less';

Below this line, there are myriad variables you can override. This is just a sampling. The rest of the variables are here, and you’ll need to include them by their @ and can change it to whatever you wish:

@primary-color: #1890ff; // primary color for all components
@link-color: #1890ff; // link color
@success-color: #52c41a; // success state color
@warning-color: #faad14; // warning state color
@error-color: #f5222d; // error state color
@font-size-base: 14px; // major text font size
@heading-color: rgba(0, 0, 0, 0.85); // heading text color
@text-color: rgba(0, 0, 0, 0.65); // major text color
@text-color-secondary: rgba(0, 0, 0, 0.45); // secondary text color
@disabled-color: rgba(0, 0, 0, 0.25); // disable state color
@border-radius-base: 4px; // major border radius
@border-color-base: #d9d9d9; // major border color
@box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.15); // major shadow for layers

We’re good to go! There’s no need to import what we need into every component because Nuxt will now take care of that. If you’d like to override very specific styles not included in the variables, you can find the associative classes and override them in your layouts/default.vue file as well. and Nuxt allow you a great framework for building apps very quickly and with ease. Enjoy!

The post Setting up and Customizing the Ant Design System in a Nuxt App appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

How to Get Handwriting Animation With Irregular SVG Strokes

Post pobrano z: How to Get Handwriting Animation With Irregular SVG Strokes

I wanted to do a handwriting animation for calligraphy fonts — the kind where the words animate like they are being written by an invisible pen. Because calligraphy fonts have uneven stroke widths (they actually aren’t even strokes in terms of SVG), it was near impossible to do this sort of thing with typical path animation techniques. But I found an innovative application of SVG masking to achieve this affect in matter of minutes. 

While researching how to do this, I gathered information from multiple sources. I combined them together and was able to create the final effect.

Let’s make this together!

SVG masking

If the stroke width of all the letters in a word or sentence are even throughout, then Craig Roblewsky has a nice way to animate handwriting. This is a clever technique that animates the SVG stroke-dasharray and stroke-offset attributes.

Calligraphy fonts like we want to animate here have uneven stroke width throughout the letters, hence it will need to be a <path> and animating it in that way will not work. The trick will be to use SVG masking.

Let’s start by figuring out what font we want to use. The one I’ll be using throughout this article is HaveHeartOne, which has a nice brush stroke appearance that is perfect for handwriting.

The idea is to create a <mask> out of same sentence we want to animate, then place it on top of the sentence. In other words, there will be two layers of same sentence. Since the mask sits on top, we’ll make it white so it will hide the original sentence below it. We will animate the mask so the bottom layer is revealed as the animation runs.

Making the layers

The foundation of this trick is that we’re actually going to create two separate layers, one on top of the other:

  1. The bottom layer is the words with the desired font (in my case it is HaveHeartOne).
  2. The top layer is a handcrafted path approximating the words.

Creating the handcrafted path isn’t as hard as you might think. We need a continuous path to animate and reveal the sentence. That means no <text> for this. But, many illustrates apps — including Illustrator — can convert letters to paths:

  1. Select the words.
  2. Open the “Properties” panel and click Create outline.

And, like magic, the letters become outlines with vector points that follow the shape.

Showing the words Marketing Lab in red in Illustrator wrapped in blue vector points.
Imagine drawing all that by hand!

At this point it is very important to give meaningful names to these paths, which are stored as layers. When we expect this to SVG, the app will generate code and it uses those layer names as the IDs and classes.

Showing the Illustrator layers of the letters with proper naming.
Those names are much nicer that what would have been auto-generated.

Notice how individual letters have a fill but no stroke:

Showing the letter M selected in Illustrator with the properties panel open indicating there is no stroke on the shape.

In SVG, we can animate the stroke in the way we want to, so we’re going to need to create that as our second main layer, the mask. We can use the pen tool to trace the letters.

  1. Select the pen tool.
  2. Set the Fill option to “None.”
  3. The stroke width will depend on the font you’re using. I’m setting the Stroke Width option to 5px and setting its color to black.
  4. Start drawing!

My pen tool skills aren’t great, but that’s OK. What’s important isn’t perfection, but that the mask covers the layer below it.

Create a mask for each letters and remember to use good names for the layers. And definitely reuse masks where there are more than one of the same letter — there’s no need to re-draw the same “A” character over and over.

Showing the Marketing Lab letter shapes completely covered by the black outline layers.


Next up, we need to export the SVG file. That will likely depend on the application you are using. In Illustrator, you can do that with File → Export → Export as → SVG

SVG options popup will open, below is the preferred setting to export for this example.

Showing the SVG export options in Illustrator.

Now, not all apps will export SVG the same exact way. Some do an excellent job at generating slim, efficient code. Others, not so much. Either way, it’s a good idea to crack open the file in a code editor 

When we’re working with SVG, there are a few tips to consider to help make them as light as possible for the sake of performance:

  1. The fewer points, the lighter the file.
  2. Using a smaller viewBox can help.
  3. There are plenty of tools to optimize SVG even further.

Manually editing the SVG code

Now, not all apps will export SVG the same exact way. Some do an excellent job at generating slim, efficient code. Others, not so much. Either way, it’s a good idea to crack open the file in a code editor and make a few changes.

Some things worth doing:

  1. Give the <svg> element width and height attributes that are set to size the final design.
  2. Use the <title> element. Since we’re working with paths, the words aren’t actually recognized by screen readers. If you need them to be read when in focus, then this will do the trick.
  3. There will likely be group elements (<g>) with the IDs based on the layers that were named in the illustration app. In this specific demo, I have two group elements:  #marketing-lab (the outline) and #marketing-masks (the masks). Move the masks into a <defs> element. This will hide it visually, which is what we want.
  4. There will likely be paths inside of the masks group. If so, go ahead and remove the transform attribute from them.
  5. Wrap each path element in a <mask> and give them a .mask class and an ID that indicates which letter is masked.

For example:

<mask id="mask-marketing-M">
  <path class="mask" id="mask-M" ... />

Inside the outline group (which I’ve given an ID of #marketing-lab), apply the mask to the respective character path element by using mask="url(#mask-marketing-M)".

<g id="marketting-lab">
  <path mask="url(#mask-marketing-M)" id="marketting-char-M" d="M427,360, ... " />

Here’s the code for one character using all the above modifications:

<svg xmlns="" viewBox="0 0 381 81" class="marketing-lab">
  <title>Marketing Lab</title>
    <g id="marketing-masks">
      <mask id="mask-marketing-M">
        <path class="mask" id="mask-M"
          d="M375.5, ... ,9-10" stroke-linecap="square" stroke-linejoin="bevel" stroke-width="7" />
  <g id="marketting-lab">
      mask="url(#mask-marketing-M)" id="marketting-char-M" 
      d="M427,360.22c-.11.08-.17.14-.17.18H427c0" />

Finally, we will add CSS for the .mask element that overrides stroke color with white so it is hidden against the document’s background color.

.mask {
  fill: none;
  stroke: #fff;


We’re going to animate the CSS stroke-dasharray property to get the continuous line reveal effect. We can do the animation with either CSS and JavasScript or with Greensock (GSAP). We’ll look at both approaches.

CSS and JavaScript 

It’s fairly straightforward to do this in CSS alone. You can use JavaScript to calculate the path length and then animate it using that returned value. If you do not want to use JavaScript at all, then you can calculate the path length once and hardcode that value into the CSS.

/* Set the stroke-dasharray and stroke-dashoffset */
.mask {
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;

/* Animation the stroke-dashoffset to a zero length */
@keyframes strokeOffset {
  to {
    stroke-dashoffset: 0;

/* Apply the animation to each mask */
#mask-M {
  animation: strokeOffset 1s linear forwards;

JavaScript can help with the counting if you’d prefer to go that route instead:

// Put the masks in an array
const masks = ['M', 'a', 'r', 'k-1', 'k-2', 'e', 't-line-v', 't-line-h', 'i-2', 'i-dot', 'n', 'g', 'lab-l', 'lab-a', 'lab-b']

masks.forEach((mask, index, el) => {
  const id = `#mask-${mask}` // Prepend #mask- to each mask element name
  let path = document.querySelector(id)
  const length = path.getTotalLength() // Calculate the length of a path = length; // Set the length to stroke-dasharray in the styles = length; // Set the length to stroke-dashoffset in the styles
CodePen Embed Fallback


GSAP has a drawSVG plugin which allows you to progressively reveal (or hide) the stroke of an SVG <path>, <line>, <polyline>, <polygon>, <rect>, or <ellipse>. Under the hood, it’s using the CSS stroke-dashoffset and stroke-dasharray properties. 

Here’s how it works:

  1. Include GSAP and drawSVG scripts in the code.
  2. Hide the graphic initially by using autoAlpha.
  3. Create a timeline.
  4. Set autoAlpha to true for the graphic.
  5. Add all the character path masks IDs to the timeline in proper sequence.
  6. Use drawSVG to animate all characters.
CodePen Embed Fallback


  1. Animated Drawing Line in SVG by Jake Archibald
  2. Creating My Logo Animation by Cassie Evans

The post How to Get Handwriting Animation With Irregular SVG Strokes appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Defining “View Source”

Post pobrano z: Defining “View Source”

Last time there was a little flurry of activity around the concept of “View Source,” I did get the sense that not everyone was on the same page about what that even means. Jim Nielsen:

First, when we talk about “View Source” what precisely are we talking about? I think this is an important point to clarify, as it sometimes goes unsaid and therefore a lot of assumptions sneak into the conversation and we might realize we’re not all talking about the same thing.

There are three things that people might be talking about:

  1. View source code (the code that generates the HTML delivered over the network)
  2. View page source (the HTML delivered over the network)
  3. View runtime source (the living HTML, a.k.a the DOM)

I’ll assign what I think are the values of each are, as slices of a pie chart:

  1. 10%
  2. 5%
  3. 85%

Every major browser ships with built-in DevTools where you can easily peak at the “runtime source.” That’s where the vast bulk of value is to me. If browsers ever talked about removing that, I’m sure we’d all be up in arms. Even for non-developers, the existence of this tool might be the spark that grows baby web developers.

DevTools also provides a way to view the HTML delivered over the network, hence my hardline stance from before:

I literally don’t care at all about View Source and wouldn’t miss it if it was removed from browsers. I live in DevTools, and I’ll bet you do too. It entirely supersedes View Source, as you can quite literally view source inside it if you’d like.

Jim’s post explains the difference between all three types of “viewing source” in great detail. For sites that are built entirely from client-side JavaScript, viewing the HTML over the wire is nearly useless. But if you could see the whole codebase (say if it was open-source on GitHub), there is certainly value there.

Direct Link to ArticlePermalink

The post Defining “View Source” appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

How to Simplify SVG Code Using Basic Shapes

Post pobrano z: How to Simplify SVG Code Using Basic Shapes

There are different ways to work with icons, but the best solution always includes SVG, whether it’s implemented inline or linked up as an image file. That’s because they’re “drawn” in code, making them flexible, adaptable, and scalable in any context.

But when working with SVG, there’s always the chance that they contain a lot of unnecessary code. In some cases, the code for an inline SVG can be long that it makes a document longer to scroll, uncomfortable to work with, and, yes, a little bit heavier than it needs to be.

We can work around this reusing chunks of code with the <use> element or apply native variables to manage our SVG styles from one place. Or, if we’re working in a server-side environment, we can always sprinkle in a little PHP (or the like) to extract the contents of the SVG file instead of dropping it straight in.

That’s all fine, but wouldn’t be great if we could solve this at the file level instead of resorting to code-based approaches? I want to focus on a different perspective: how to make the same figures with less code using basic shapes. This way, we get the benefits of smaller, controllable, and semantic icons in our projects without sacrificing quality or visual changes. I’ll go through different examples that explore the code of commonly used icons and how we can redraw them using some of the easiest SVG shapes we can make.

Here are the icons we’ll be working on:

Showing an close icon in the shape of an x, a clock with the hands pointing at 3 o-clock, and a closed envelope.

Let’s look at the basic shapes we can use to make these that keep the code small and simple.

Psssst! Here is a longer list of simple icons I created on! After this article, you’ll know how to modify them and make them your own.

Simplifying a close icon with the <line> element

This is the code for the “close” or “cross” icon that was downloaded from and built by pixel-perfect:

CodePen Embed Fallback

In this example, everything is happening inside the <path> with lots of commands and parameters in the data attribute (d). What this SVG is doing is tracing the shape from its borders.

A quick demonstration using

If you are familiar with Illustrator, this is the equivalent of drawing two separate lines, converting them to shape, then combining both with the pathfinder to create one compound shape.

The <path> element allows us to draw complex shapes, but in this case, we can create the same figure with two lines, while keeping the same appearance:

<svg xmlns="" viewBox="0 0 50 50" width="50" height="50" overflow="visible" stroke="black" stroke-width="10" stroke-linecap="round">
   <line x1="0" y1="0" x2="50" y2="50" />
   <line x1="50" y1="0" x2="0" y2="50" />

We started by defining a viewBox that goes from 0,0 to 50,50. You can choose whatever dimensions you prefer; the SVG will always scale nicely to any width and height you define. To make things easier, in this case, I also defined an inline width and height of 50 units, which avoids extra calculations in the drawing.

To use the <line> element, we declare the coordinates of the line’s first point and the coordinates of its last point. In this specific case, we started from x=0 y=0 and ended at x=50 y=50.

Grid of the coordinate system.

Here’s how that looks in code:

<line x1="0" y1="0" x2="50" y2="50" />

The second line will start from x=50 y=0 and end at x=0 y=50:

<line x1="50" y1="0" x2="0" y2="50" />

An SVG stroke doesn’t have a color by default — that’s why we added the black value on the stroke attribute. We also gave the stroke-width attribute a width of 10 units and the stroke-linecap a round value to replicate those rounded corners of the original design. These attributes were added directly to the <svg> tag so both lines will inherit them.

<svg ... stroke="black" stroke-width="10" stroke-linecap="round" ...>

Now that the stroke is 10 units bigger that its default size of 1 unit, the line might get cropped by the viewBox. We can either move the points 10 units inside the viewBox or add overflow=visible to the styles.

The values that are equal to 0 can be removed, as 0 is the default. That means the two lines end up with two very small lines of code:

<line x2="50" y2="50" />
<line x1="50" y2="50" />

Just by changing a <path> to a <line>, not only did we make a smaller SVG file, but a more semantic and controllable chunk of code that makes any future maintenance much easier. And the visual result is exactly the same as the original.

CodePen Embed Fallback

Same cross, different code.

Simplifying a clock icon with the <circle> and <path> elements

I took this example of a clock icon created by barracuda from The Noun Project:

CodePen Embed Fallback

This shape was also drawn with a <path>, but we also have a lot of namespaces and XML instructions related to the software used and the license of the file that we can delete without affecting the SVG. Can you tell what illustration editor was used to create the icon?

Let’s recreate this one from scratch using a circle and a path with simpler commands. Again, we need to start with a viewBox, this time from 0,0 to 100,100, and with a width and height matching those units.

<svg xmlns="" viewBox="0 0 100 100" width="100" height="100" fill="none" stroke="black" stroke-width="10" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="50" cy="50" r="40"/>
  <path d="M50 25V50 H75" /> 

We keep the same styles as the previous icon inside the <svg> tag. fill is black by default, so we need to explicitly give it a none value to remove it. Otherwise, the circle will have have a solid black fill, obscuring the other shapes.

To draw the <circle> we need to indicate a center point from where the radius will sit. We can achieve that with cx (center x) and cy (center y). Then r (radius) will declare how big our circle will be. In this example, the radius is slightly smaller than the viewBox, so it doesn’t get cropped when the stroke is 10 units wide.

What’s up with all those letters? Check out Chris Coyier’s illustrated guide for a primer on the SVG syntax.

We can use a <path> for the clock hands because it has some very useful and simple commands to draw. Inside the d (data) we must start with the M (move to) command followed by the coordinates from where we’ll start drawing which, in this example, is 50,25 (near the top-center of the circle). 

After the V (vertical) command, we only need one value as we can only move up or down with a negative or positive number. A positive number will go down. The same for H (horizontal) followed by a positive number, 75, that will draw toward the right. All commands are uppercase, so the numbers we choose will be points in the grid. If we decided to use lowercase (relative commands) the numbers will be the amount of units that we move in one direction and not an absolute point in the coordinate system.

CodePen Embed Fallback

Same clock, different code.

Simplifying an envelope icon with the <rect> and <polyline> elements

I drew the envelope icon in Illustrator without expanding the original shapes. Here’s the code that came from the export:

CodePen Embed Fallback

Illustrator offers some SVG options to export the graphic. I chose “Style Elements” in the “CSS Properties” dropdown so I can have a <style> tag that contains classes that I might want to move to a CSS file. But there are different ways to apply the styles in SVG, of course.

We already have basic shapes in this code! I unselected the “Shape to paths” option in Illustrator which helped a lot there. We can optimize this further with SVGOMG to remove the comments, XML instructions, and unnecessary data, like empty elements. From there, we can manually remove other extras, if we need to.

We already have something a little more concise:

<svg version="1.1" id="Layer_1" xmlns="" x="0" y="0" viewBox="0 0 310 190" xml:space="preserve">
  </style><rect x="5" y="5" class="st0" width="300" height="180"/>
  <polyline class="st0" points="5 5 155 110 305 5"/>

We can remove even more stuff without affecting the visual appearance of the envelope, including: 

  • version="1.1" (this has been deprecated since SVG 2)
  • id="Layer_1" (this has no meaning or use)
  • x="0" (this is a default value)
  • y="0" (this is a default value)
  • xml:space="preserve" (this has been deprecated since SVG 2)
<svg xmlns="" x="0" y="0" viewBox="0 0 310 190">
  <rect x="5" y="5" class="st0" width="300" height="180"/>
  <polyline class="st0" points="5 5 155 110 305 5"/>

We can move the CSS styles to a separate stylesheet if we really want to get really aggressive.

<rect> needs a starting point from where we’ll extend a width and a height, so let’s use  x="5" and y="5" which is our top-left point. From there, we will create a rectangle that is 300 units wide with a height of 180 units. Just like the clock icon, we’ll use 5,5 as the starting point because we have a 10-unit stroke that will get cropped if the coordinates were located at 0,0.

<polyline> is similar to <line>, but with an infinite amount of points that we define, like pairs of coordinates, one after the other, inside the points attribute, where the first number in the pair will represent x and the second will be y. It’s easier to read the sequence with commas, but those can be replaced with whitespace without having an impact on the result.

CodePen Embed Fallback

Same envelope, different code.

Bonus shapes!

I didn’t include examples of icons that can be simplified with <polygon> and <ellipse> shapes, but here is a quick way to use them.

<polygon> is the same as <polyline>, only this element will always define a closed shape. Here’s an example that comes straight from MDN:

CodePen Embed Fallback

Remember the circle we drew earlier for the clock icon? Replace the r (radius) with rx and ry. Now you have two different values for radius. Here’s another example from MDN:

CodePen Embed Fallback

Wrapping up

We covered a lot here in a short amount of time! While we used examples to demonstrates the process of optimizing SVGs, here’s what I hope you walk away with from this post:

  • Remember that compression starts with how the SVG is drawn in illustration software.
  • Use available tools, like SVOMG, to compress SVG.
  • Remove unnecessary metadata by hand, if necessary.
  • Replace complex paths with basic shapes.
  • <use> is a great way to “inline” SVG as well as for establishing your own library of reusable icons.

How many icons can be created by combining these basic shapes? 

I’m working my list on, I’ll be constantly uploading more icons and features here, and now you know how to easily modified them just by changing a few numbers. Go ahead and make them yours!

The post How to Simplify SVG Code Using Basic Shapes appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Beyond Media Queries: Using Newer HTML & CSS Features for Responsive Designs

Post pobrano z: Beyond Media Queries: Using Newer HTML & CSS Features for Responsive Designs

Beyond using media queries and modern CSS layouts, like flexbox and grid, to create responsive websites, there are certain overlooked things we can do well to make responsive sites. In this article, we’ll dig into a number tools (revolving around HTML and CSS) we have at the ready, from responsive images to relatively new CSS functions that work naturally whether we use media queries or not.

In fact, media queries become more of a complement when used with these features rather than the full approach. Let’s see how that works.

Truly responsive images

Remember when we could just chuck width: 100% on images and call it a day? That still works, of course, and does make images squishy, but there are a number of downsides that come with it, the most notable of which include:

  • The image might squish to the extent that it loses its focal point.
  • Smaller devices still wind up downloading the full size image.

When using images on the web, we have to make sure they’re optimized in terms of their resolution and size. The reason is to ensure that we have the right image resolution to fit the right device, so we don’t end up downloading really large and heavy images for smaller screens which could end up reducing the performance of a site. 

In simple terms, we’re making sure that larger, high-resolution images are sent to larger screens, while smaller, low-resolution variations are sent to smaller screens, improving both performance and user experience.

HTML offers the <picture> element that allows us specify the exact image resource that will be rendered based on the media query we add. As described earlier, instead of having one image (usually a large, high-resolution version) sent to all screen sizes and scaling it to the viewport width, we specify a set of images to serve in specific situations.

  <source media="(max-width:1000px)" srcset="picture-lg.png">
  <source media="(max-width:600px)" srcset="picture-mid.png">
  <source media="(max-width:400px)" srcset="picture-sm.png">
  <img src="picture.png" alt="picture"">

In this example, picture.png is the full-size image. From there, we define the next-largest version of the image, picture-lg.png, and the size reduces in descending order until the smallest version, picture-sm.png. Note that we’re still using media queries in this approach, but it’s the <picture> element itself that is driving the responsive behavior rather than defining breakpoints in the CSS.

The media queries are added appropriately to scale with the sizes of the picture:

  • Viewports that are 1000px and above get picture.png.
  • Viewports that are between 601px and 999px get picture-lg.png.
  • Viewports that are between 401px and 600px get picture-sm.png.
  • Any thing smaller than 400px gets picture-sm.png.

Interestingly, we can also label each image by image density —  1x, 2x, 3x and so forth — after the URL. This works if we have made the different images in proportion to each other (which we did). This allows the browser to determine which version to download based on the screen’s pixel density in addition to the viewport size. But note how many images we wind up defining:

  <source media="(max-width:1000px)" srcset="picture-lg_1x.png 1x, picture-lg_2x.png 2x, picture-lg_3x.png 3x">
  <source media="(max-width:600px)" srcset="picture-mid_1x.png 1x, picture-mid_2x.png 2x, picture-mid_3x.png 3x">
  <source media="(max-width:400px)" srcset="picture-small_1x.png 1x, picture-small_2x.png 2x, picture-small_1x.png 3x">
  <img src="picture.png" alt="picture"">

Let’s look specifically at the two tags nested inside the <picture> element: <source> and <img>.

The browser will look for the first <source> element where the media query matches the current viewport width, and then it will display the proper image (specified in the srcset attribute). The <img> element is required as the last child of the <picture> element, as a fallback option if none of the initial source tags matches.

We can also use image density to handle responsive images with just the <img> element using the srcset attribute:

  flower4x.png 4x,
  flower3x.png 3x,
  flower2x.png 2x,
  flower1x.png 1x

Another thing we can do is write media queries in the CSS based on the screen resolution (usually measured in dots per inch, or dpi) of the device itself and not just the device viewport. What this means is that instead of:

@media only screen and (max-width: 600px) {
  /* Style stuff */

We now have:

@media only screen and (min-resolution: 192dpi) {
  /* Style stuff */

This approach lets us dictate what image to render based the screen resolution of the device itself, which could be helpful when dealing with high resolution images. Basically, that means we can display high quality pictures for screens that support higher resolutions and smaller versions at lower resolutions. It’s worth noting that, although mobile devices have small screens, they’re usually high resolution. That means it’s probably not the best idea rely on resolution alone when determining which image to render. It could result in serving large, high-resolution images to really small screens, which may not be the version we really want to display at such a small screen size.

body {
  background-image : picture-md.png; /* the default image */

@media only screen and (min-resolution: 192dpi) {
  body {
    background-image : picture-lg.png; /* higher resolution */

What <picture> gives us is basically the ability to art direct images. And, in keeping with this idea, we can leverage CSS features, like the object-fit property which, when used with object-position, allows us to crop images for better focal points while maintaining the image’s aspect ratio.

So, to change the focal point of an image:

@media only screen and (min-resolution: 192dpi) {
  body {
    background-image : picture-lg.png;
    object-fit: cover;
    object-position: 100% 150%; /* moves focus toward the middle-right */

Setting minimum and maximum values in CSS

The min() function specifies the absolute smallest size that an element can shrink to. This function proves really useful in terms of helping text sizes to properly scale across different screen sizes, like never letting fluid type to drop below a legible font size:

html {
  font-size: min(1rem, 22px); /* Stays between 16px and 22px */

min() accepts two values, and they can be relative, percentage, or fixed units. In this example, we’re telling the browser to never let an element with class .box go below 45% width or 600px, whichever is smallest based on the viewport width:

.box {
  width : min(45%, 600px)

If 45% computes to a value smaller than 600px, the browser uses 45% as the width. Conversely, if  45% computes to a value greater than 600px, then 600px will be used for the element’s width.

The same sort of thing goes for the max() function. It also accepts two values, but rather than specifying the smallest size for an element, we’re defining the largest it can get.

.box {
  width : max(60%, 600px)

If 60% computes to a value smaller than 600px, the browser uses 60% as the width. On the flip side, if 60% computes to a value greater than 600px, then 600px will be used as the element’s width.

And, hey, we can even set a minimum and maximum range instead using the minmax() function:

.box {
  width : minmax( 600px, 50% ); /* at least 600px, but never more than 50% */

Clamping values

Many of us have been clamoring for clamp() for some time now, and we actually have broad support across all modern browsers (sorry, Internet Explorer). clamp() is the combination of the min() and max() functions, accepting three parameters:

  1. the minimum value,
  2. the preferred value, and
  3. the maximum value

For example:

.box {
  font-size : clamp(1rem, 40px, 4rem)

The browser will set the font at 1rem until the computed value of 1rem is larger than 40px. And when the computed value is above 40px? Yep, the browser will stop increasing the size after it hits 4rem. You can see how clamp() can be used to make elements fluid without reaching for media queries.

Working with responsive units

Have you ever built a page with a large heading or sub-heading and admired how great it looked on a desktop screen, only to check it on a mobile device and find out that’s it’s too large? I have definitely been in this situation and in this section I’ll be explaining how to handle such problems.

In CSS, you can determine sizes or lengths of elements using various units of measurements, and the most used units of measurements includes: px, em, rem, %, vw, and vh. Although, there are several more units that aren’t used as frequently. What’s of interest to us is that px can be considered an absolute unit, while the rest are considered relative units.

Absolute units

A pixel (px) is considered an absolute unit mainly because it’s fixed and does not change based on the measurement of any other element. It can be considered as the base, or root, unit that some other relative units use. Trying to use pixels for responsive behavior can bump into issues because it’s fixed, but they’re great if you have elements that should not be resized at all.

Relative units

Relative units, like %, em, and rem, are better suited to responsive design mainly because of their ability to scale across different screen sizes.

vw: Relative to the viewport’s width
vh: Relative to the viewport’s height
rem: Relative to the root (<html>) element (default font-size is usually 16px )
em: Relative to the parent element
%: Relative to the parent element

Again, the default font size for most browsers is 16px and and that’s what rem units use to generate their computed values. So, if a user adjusts the font size on the browser, everything on the page scales properly depending on the root size. For example, when dealing a root set at 16px, the number you specify will multiply that number times the default size. For example:

.8rem = 12.8px (.8 * 16)
1rem = 16px (1 * 16)
2rem = 32px (2 * 16)

What if either you or the user changes the default size? As we said already, these are relative units and the final size values will be based off of the new base size. This proves useful within media queries, where you just change the font size and the entire page scales up or down accordingly.

For example, if you changed the font-size to 10px within the CSS, then the calculated sizes would end up being:

html {
  font-size : 10px;
1rem = 10px (1 * 10)
2rem = 20px (2 * 10)
.5rem = 5px (.5 * 10)

Note: This also applies to percentage %. For instance:

100% = 16px;
200% = 32px; 
50% = 8px;

And what’s the difference between rem and em units? It’s what the unit uses as its base element. rem calculates values using the font size of the root (<html>) element, whereas an element declaring em values references the font size of the parent element that contains it. If the size of specified parent element is different from the root element (e.g. the parent elements is 18px but the root element is 16px) then em and rem will resolve to different computed values. This gives us more fine-grained control of how our elements respond in different responsive contexts.

vh is an acronym for viewport height, or the viewable screen’s height. 100vh represent 100% of the viewport’s height (depending on the device). In the same vein, vw stands for viewport width, meaning the viewable screen’s width of the device, and 100vw literally represents 100% of the viewport’s width.

Moving beyond media queries

See that? We just looked at a number of really powerful and relatively new HTML and CSS features that give us additional (and possible more effective) ways to build for responsiveness. It’s not that these new-fangled techniques replace what we’ve been doing all along. They are merely more tools in our developer tool belt that give us greater control to determine how elements behave in different contexts. Whether it’s working with font sizes, resolutions, widths, focal points, or any number of things, we have more fine-grain control of the user experience than ever before.

So, next time you find yourself working on a project where you wish you had more control over the exact look and feel of the design on specific devices, check out what native HTML and CSS can do to help — it’s incredible how far things have come along.

The post Beyond Media Queries: Using Newer HTML & CSS Features for Responsive Designs appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.