{"id":262598,"date":"2017-12-27T07:31:41","date_gmt":"2017-12-27T14:31:41","guid":{"rendered":"http:\/\/css-tricks.com\/?p=262598"},"modified":"2017-12-27T07:34:22","modified_gmt":"2017-12-27T14:34:22","slug":"sliding-nightmare-understanding-range-input","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/sliding-nightmare-understanding-range-input\/","title":{"rendered":"A Sliding Nightmare: Understanding the Range Input"},"content":{"rendered":"

You may have already seen a bunch<\/a> of<\/a> tutorials<\/a> on how to style the range input. While this is another article on that topic, it’s not about how to get any specific visual result. Instead, it dives into browser inconsistencies, detailing what each does to display that slider on the screen. Understanding this is important because it helps us have a clear idea about whether we can make our slider look and behave consistently across browsers and which styles are necessary to do so.<\/p>\n

<\/p>\n

Looking inside a range input<\/h3>\n

Before anything else, we need to make sure the browser exposes the DOM inside<\/em> the range input.<\/p>\n

In Chrome, we bring up DevTools, go to Settings<\/strong>, Preferences<\/strong>, Elements<\/strong> and make sure the Show user agent shadow DOM<\/strong> option is enabled.<\/p>\n

\"Series
Sequence of Chrome screenshots illustrating the steps from above.<\/figcaption><\/figure>\n

In Firefox, we go to about:config<\/code> and make sure the devtools.inspector.showAllAnonymousContent<\/code> flag is set to true<\/code>.<\/p>\n

\"Series
Sequence of Firefox screenshots illustrating the steps from above.<\/figcaption><\/figure>\n

For a very long time, I was convinced that Edge offers no way of seeing what’s inside such elements. But while messing with it, I discovered that where there’s a will and (and some dumb luck) there’s a way! We need to bring up DevTools, then go to the range input<\/code> we want to inspect, right click it, select Inspect Element<\/strong> and bam, the DOM Explorer panel now shows the structure of our slider!<\/p>\n

\"Series
Sequence of Edge screenshots illustrating the steps from above.<\/figcaption><\/figure>\n

Apparently, this is a bug<\/a>. But it’s also immensely useful, so I’m not complaining.<\/p>\n

The structure inside<\/h3>\n

Right from the start, we can see a source for potential problems: we have very different beasts inside for every browser.<\/p>\n

In Chrome, at the top of the shadow DOM, we have a div<\/code> we cannot access anymore. This used to be possible back when \/deep\/<\/code> was supported, but then the ability to pierce through the shadow barrier was deemed to be a bug, so what used to be a useful feature was dropped. Inside this div<\/code>, we have another one for the track and, within the track div<\/code>, we have a third div<\/code> for the thumb. These last two are both clearly labeled with an id<\/code> attribute, but another thing I find strange is that, while we can access the track with ::-webkit-slider-runnable-track<\/code> and the thumb with ::-webkit-slider-thumb<\/code>, only the track div<\/code> has a pseudo<\/code> attribute with this value.<\/p>\n

\"Chrome
Inner structure in Chrome.<\/figcaption><\/figure>\n

In Firefox, we also see three div<\/code> elements inside, only this time they’re not nested – all three of them are siblings. Furthermore, they’re just plain div<\/code> elements, not labeled by any attribute, so we have no way of telling which is which component when looking at them for the first time. Fortunately, selecting them in the inspector highlights the corresponding component on the page and that’s how we can tell that the first is the track, the second is the progress and the third is the thumb.<\/p>\n

\"Firefox
Inner structure in Firefox.<\/figcaption><\/figure>\n

We can access the track (first div<\/code>) with ::-moz-range-track<\/code>, the progress (second div<\/code>) with ::-moz-range-progress<\/code> and the thumb (last div<\/code>) with ::-moz-range-thumb<\/code>.<\/p>\n

The structure in Edge is much more complex, which, to a certain extent, allows for a greater degree of control over styling the slider. However, we can only access the elements with -ms-<\/code> prefixed IDs, which means there are also a lot of elements we cannot access, with baked in styles we’d often need to change, like the overflow: hidden<\/code> on the elements between the actual input<\/code> and its track or the transition<\/code> on the thumb’s parent.<\/p>\n

\"Edge
Inner structure in Edge.<\/figcaption><\/figure>\n

Having a different structure and being unable to access all the elements inside in order to style everything as we wish means that achieving the same result in all browsers can be very difficult, if not even impossible, even if having to use a different pseudo-element for every browser helps with setting individual styles.<\/p>\n

We should always aim to keep the individual styles to a minimum, but sometimes it’s just not possible, as setting the same style can produce very different results due to having different structures. For example, setting properties such as opacity<\/code> or filter<\/code> or even transform<\/code> on the track would also affect the thumb in Chrome and Edge (where it’s a child\/ descendant of the track), but not in Firefox (where it’s its sibling).<\/p>\n

The most efficient way I’ve found to set common styles is by using a Sass mixin because the following won’t work:<\/p>\n

input::-webkit-slider-runnable-track, \r\ninput::-moz-range-track, \r\ninput::-ms-track { \/* common styles *\/ }<\/code><\/pre>\n

To make it work, we’d need to write it like this:<\/p>\n

input::-webkit-slider-runnable-track { \/* common styles *\/ }\r\ninput::-moz-range-track { \/* common styles *\/ }\r\ninput::-ms-track { \/* common styles *\/ }<\/code><\/pre>\n

But that’s a lot of repetition and a maintainability nightmare. This is what makes the mixin solution the sanest option: we only have to write the common styles once so, if we decide to modify something in the common styles, then we only need to make that change in one place – in the mixin.<\/p>\n

@mixin track() { \/* common styles *\/ }\r\n\r\ninput {\r\n  &::-webkit-slider-runnable-track { @include track }\r\n  &::-moz-range-track { @include track }\r\n  &::-ms-track { @include track }\r\n}<\/code><\/pre>\n

Note that I’m using Sass here, but you may use any other preprocessor. Whatever you prefer is good as long as it avoids repetition and makes the code easier to maintain.<\/p>\n

Initial styles<\/h3>\n

Next, we take a look at some of the default styles the slider and its components come with in order to better understand which properties need to be set explicitly to avoid visual inconsistencies between browsers.<\/p>\n

Just a warning in advance: things are messy and complicated. It’s not just that we have different defaults in different browsers, but also changing a property on one element may change another in an unexpected way (for example, when setting a background<\/code> also changes the color<\/code> and adds a border<\/code>).<\/p>\n

WebKit browsers and Edge (because, yes, Edge also applies a lot of WebKit prefixed stuff) also have two levels of defaults for certain properties (for example those related to dimensions, borders, and backgrounds), if we may call them that – before setting -webkit-appearance: none<\/code> (without which the styles we set won’t work in these browsers) and after setting it. The focus is going to be however on the defaults after setting -webkit-appearance: none<\/code> because, in WebKit browsers, we cannot style the range input without setting this and the whole reason we’re going through all of this is to understand how we can make our lives easier when styling sliders.<\/p>\n

Note that setting -webkit-appearance: none<\/code> on the range input<\/code> and on the thumb (the track already has it set by default for some reason) causes the slider to completely disappear in both Chrome and Edge. Why that happens is something we’ll discuss a bit later in this article.<\/p>\n

The actual range input element<\/h4>\n

The first property I’ve thought about checking, box-sizing<\/code>, happens to have the same value in all browsers – content-box<\/code>. We can see this by looking up the box-sizing<\/code> property in the Computed<\/strong> tab in DevTools.<\/p>\n

\"Comparative
The box-sizing<\/code> of the range input<\/code>, comparative look at all three browsers (from top to bottom: Chrome, Firefox, Edge).<\/figcaption><\/figure>\n

Sadly, that’s not an indication of what’s to come. This becomes obvious once we have a look at the properties that give us the element’s boxes – margin<\/code>, border<\/code>, padding<\/code>, width<\/code>, height<\/code>.<\/p>\n

By default, the margin<\/code> is 2px<\/code> in Chrome and Edge and 0 .7em<\/code> in Firefox.<\/p>\n

Before we move on, let’s see how we got the values above. The computed length values we get are always px<\/code> values.<\/p>\n

However, Chrome shows us how browser styles were set (the user agent stylesheet rule sets on a grey background). Sometimes the computed values we get weren’t explicitly set, so that’s no use, but in this particular case, we can see that the margin<\/code> was indeed set as a px<\/code> value.<\/p>\n

\"Screenshot
Tracing browser styles in Chrome, the margin<\/code> case.<\/figcaption><\/figure>\n

Firefox also lets us trace the source of the browser styles in some cases, as shown in the screenshot below:<\/p>\n

\"Screenshot
Tracing browser styles in Firefox and how this fails for the margin<\/code> of our range input<\/code>.<\/figcaption><\/figure>\n

However, that doesn’t work in this particular case, so what we can do is look at the computed values in DevTools and then checking whether these computed values change in one of the following situations:<\/p>\n

    \n
  1. When changing the font-size<\/code> on the input<\/code> or on the html<\/code>, which entails is was set as an em<\/code> or rem<\/code> value.<\/li>\n
  2. When changing the viewport, which indicates the value was set using %<\/code> values or viewport units. This can probably be safely skipped in a lot of cases though.<\/li>\n<\/ol>\n
    \"Gif
    Changing the font-size<\/code> of the range input<\/code> in Firefox also changes its margin<\/code> value.<\/figcaption><\/figure>\n

    The same goes for Edge, where we can trace where user styles come from, but not browser styles, so we need to check if the computed px<\/code> value depends on anything else.<\/p>\n

    \"Gif
    Changing the font-size<\/code> of the range input<\/code> in Edge doesn’t change its margin<\/code> value.<\/figcaption><\/figure>\n

    In any event, this all means margin<\/code> is a property we need to set explicitly in the input[type='range']<\/code> if we want to achieve a consistent look across browsers.<\/p>\n

    Since we’ve mentioned the font-size<\/code>, let’s check that as well. Sure enough, this is also inconsistent.<\/p>\n

    First off, we have 13.3333px<\/code> in Chrome and, in spite of the decimals that might suggest it’s the result of a computation where we divided a number by a multiple of 3<\/code>, it seems to have been set as such and doesn’t depend on the viewport dimensions or on the parent or root font-size<\/code>.<\/p>\n

    \"Screenshot
    The font-size<\/code> of the range input<\/code> in Chrome.<\/figcaption><\/figure>\n

    Firefox shows us the same computed value, except this seems to come from setting the font<\/code> shorthand to -moz-field<\/code>, which I was first very confused about, especially since background-color<\/code> is set to -moz-Field<\/code>, which ought to be the same since CSS keywords are case-insensitive. But if they’re the same, then how can it be a valid value for both properties? Apparently, this keyword is some sort of alias<\/a> for making the input look like what any input on the current OS looks like.<\/p>\n

    \"Screenshot
    The font-size<\/code> of the range input<\/code> in Firefox.<\/figcaption><\/figure>\n

    Finally, Edge gives us 16px<\/code> for its computed value and this seems to be either inherited from its parent or set as 1em<\/code>, as illustrated by the recording below:<\/p>\n

    \"Recording
    The font-size<\/code> of the range input<\/code> in Edge.<\/figcaption><\/figure>\n

    This is important because we often want to set dimensions of sliders and controls (and their components) in general using em<\/code> units so that their size relative to that of the text on the page stays the same – they don’t look too small when we increase the size of the text or too big when we decrease the size of the text. And if we’re going to set dimensions in em<\/code> units, then having a noticeable font-size<\/code> difference between browsers here will result in our range input<\/code> being smaller in some browsers and bigger in others.<\/p>\n

    For this reason, I always make sure to explicitly set a font-size<\/code> on the actual slider. Or I might set the font<\/code> shorthand, even though the other font-related properties don’t matter here at this point. Maybe they will in the future, but more on that later, when we discuss tick marks and tick mark labels.<\/p>\n

    Before we move on to borders, let’s first see the color<\/code> property. In Chrome this is rgb(196,196,196)<\/code> (set as such), which makes it slightly lighter than silver<\/code> (rgb(192,192,192)<\/code>\/ #c0c0c0<\/code>), while in Edge and Firefox, the computed value is rgb(0,0,0)<\/code> (which is solid black<\/code>). We have no way of knowing how this value was set in Edge, but in Firefox, it was set via another similar keyword, -moz-fieldtext<\/code>.<\/p>\n

    \"Comparative
    The color<\/code> of the range input<\/code>, comparative look at all three browsers (from top to bottom: Chrome, Firefox, Edge).<\/figcaption><\/figure>\n

    The border<\/code> is set to initial<\/code> in Chrome, which is equivalent to none medium currentcolor<\/code> (values for border-style<\/code>, border-width<\/code> and border-color<\/code>). How thick a medium<\/code> border is exactly depends on the browser, though it’s at least as thick as a thin<\/code> one everywhere. In Chrome in particular, the computed value we get here is 0<\/code>.<\/p>\n

    \"Screenshot
    The border<\/code> of the range input<\/code> in Chrome.<\/figcaption><\/figure>\n

    In Firefox, we also have a none medium currentcolor<\/code> value set for the border<\/code>, though here medium<\/code> seems to be equivalent to 0.566667px<\/code>, a value that doesn’t depend on the element or root font-size<\/code> or on the viewport dimensions.<\/p>\n

    \"Screenshot
    The border<\/code> of the range input<\/code> in Firefox.<\/figcaption><\/figure>\n

    We can’t see how everything was set in Edge, but the computed values for border-style<\/code> and border-width<\/code> are none<\/code> and 0<\/code> respectively. The border-color<\/code> changes when we change the color<\/code> property, which means that, just like in the other browsers, it’s set to currentcolor<\/code>.<\/p>\n

    \"Recording
    The border<\/code> of the range input<\/code> in Edge.<\/figcaption><\/figure>\n

    The padding<\/code> is 0<\/code> in both Chrome and Edge.<\/p>\n

    \"Comparative
    The padding<\/code> of the range input<\/code>, comparative look at Chrome (top) and Edge (bottom).<\/figcaption><\/figure>\n

    However, if we want a pixel-perfect result, then we need to set it explicitly because it’s set to 1px<\/code> in Firefox.<\/p>\n

    \"Screenshot
    The padding<\/code> of the range input<\/code> in Firefox.<\/figcaption><\/figure>\n

    Now let’s take another detour and check the backgrounds before we try to make sense of the values for the dimensions. Here, we get that the computed value is transparent<\/code>\/ rgba(0, 0, 0, 0)<\/code> in Edge and Firefox, but rgb(255,255,255)<\/code> (solid white<\/code>) in Chrome.<\/p>\n

    \"Comparative
    The background-color<\/code> of the range input<\/code>, comparative look at all three browsers (from top to bottom: Chrome, Firefox, Edge).<\/figcaption><\/figure>\n

    And… finally, let’s look at the dimensions. I’ve saved this for last because here is where things start to get really messy.<\/p>\n

    Chrome and Edge both give us 129px<\/code> for the computed value of the width<\/code>. Unlike with previous properties, we can’t see this being set anywhere in Chrome, which would normally lead me to believe it’s something that depends either on the parent, stretching horizontally to fit as all block<\/code> elements do (which is definitely not the case here) or on the children. There’s also a -webkit-logical-width<\/code> property taking the same 129px<\/code> value in the Computed panel. I was a bit confused by this at first, but it turns out it’s the writing-mode relative equivalent<\/a> – in other words, it’s the width<\/code> for horizontal writing-mode and the height<\/code> for vertical writing-mode.<\/p>\n

    \"Gif
    Changing the font-size<\/code> of the range input<\/code> in Chrome doesn’t change its width<\/code> value.<\/figcaption><\/figure>\n

    In any event, it doesn’t depend on the font-size<\/code> of the input<\/code> itself or of that of the root element nor on the viewport dimensions in either browser.<\/p>\n

    \"Gif
    Changing the font-size<\/code> of the range input<\/code> in Edge doesn’t change its width<\/code> value.<\/figcaption><\/figure>\n

    Firefox is the odd one out here, returning a computed value of 160px<\/code> for the default width<\/code>. This computed value does however depend on the font-size<\/code> of the range input<\/code> – it seems to be 12em<\/code>.<\/p>\n

    \"Gif
    Changing the font-size<\/code> of the range input<\/code> in Firefox also changes its width<\/code> value.<\/figcaption><\/figure>\n

    In the case of the height<\/code>, Chrome and Edge again both agree, giving us a computed value of 21px<\/code>. Just like for the width<\/code>, I cannot see this being set anywhere in the user agent stylesheet in Chrome DevTools, which normally happens when the height<\/code> of an element depends on its content.<\/p>\n

    \"Gif
    Changing the font-size<\/code> of the range input<\/code> in Chrome doesn’t change its height<\/code> value.<\/figcaption><\/figure>\n

    This value also doesn’t depend on the font-size<\/code> in either browser.<\/p>\n

    \"Gif
    Changing the font-size<\/code> of the range input<\/code> in Edge doesn’t change its height<\/code> value.<\/figcaption><\/figure>\n

    Firefox is once again different, giving us 17.3333px<\/code> as the computed value and, again, this depends on the input<\/code>‘s font-size<\/code> – it’s 1.3em<\/code>.<\/p>\n

    \"Gif
    Changing the font-size<\/code> of the range input<\/code> in Firefox also changes its height<\/code> value.<\/figcaption><\/figure>\n

    But this isn’t worse than the margin<\/code> case, right? Well, so far, it isn’t! But that’s just about to change because we’re now moving on to the track component.<\/p>\n

    The range track component<\/h4>\n

    There’s one more possibility regarding the actual input<\/code> dimensions that we haven’t yet considered: that they’re influenced by those of its components. So let’s explicitly set some dimensions on the track and see whether that influences the size of the slider.<\/p>\n

    Apparently, in this situation, nothing changes for the actual slider in the case of the width<\/code>, but we can spot more inconsistencies when it comes to the track width<\/code>, which, by default, stretches to fill the content-box<\/code> of the parent input<\/code> in all three browsers.<\/p>\n

    In Firefox, if we explicitly set a width<\/code>, any width<\/code> on the track, then the track takes this width<\/code> we give it, expanding outside of its parent slider or shrinking inside, but always staying middle aligned with it. Not bad at all, but, sadly, it turns out Firefox is the only browser that behaves in a sane manner here.<\/p>\n

    \"Gif
    Explicitly setting a width<\/code> on the track changes the width<\/code> of the track in Firefox, but not that of the parent slider.<\/figcaption><\/figure>\n

    In Chrome, the track width<\/code> we set is completely ignored and it looks like there’s no sane way of making it have a value that doesn’t depend on that of the parent slider.<\/p>\n

    \"Gif
    Changing the width<\/code> of the track doesn’t do anything in Chrome (computed value remains 129px<\/code>).<\/figcaption><\/figure>\n

    As for insane ways, using transform: scaleX(factor)<\/code> seems to be the only way to make the track wider or narrower than its parent slider. Do note doing this also causes quite a few side effects. The thumb is scaled horizontally as well and its motion is limited to the scaled down track in Chrome and Edge (as the thumb is a child of the track in these browsers), but not in Firefox, where its size is preserved and its motion is still limited to the input, not the scaled down track (since the track and thumb are siblings here). Any lateral padding<\/code>, border<\/code> or margin<\/code> on the track is also going to be scaled.<\/p>\n

    Moving on to Edge, the track again takes any width<\/code> we set.<\/p>\n

    \"Gif
    Edge also allows us to set a track width<\/code> that’s different from that of the parent slider.<\/figcaption><\/figure>\n

    This is not the same situation as Firefox however. While setting a width<\/code> greater than that of the parent slider on the track makes it expand outside, the two are not middle aligned. Instead, the left border limit of the track is left aligned with the left content limit of its range input<\/code> parent. This alignment inconsistency on its own wouldn’t be that much of a problem – a margin-left<\/code> set only on ::-ms-track<\/code> could fix it.<\/p>\n

    However, everything outside of the parent slider’s content-box<\/code> gets cut out in Edge. This is not equivalent to having overflow<\/code> set to hidden<\/code> on the actual input<\/code>, which would cut out everything outside the padding-box<\/code><\/a>, not content-box<\/code>. Therefore, it cannot be fixed by setting overflow: visible<\/code> on the slider.<\/p>\n

    This clipping is caused by the elements between the input<\/code> and the track having overflow: hidden<\/code>, but, since we cannot access these, we also cannot fix this problem. Setting everything such that no component (including its box-shadow<\/code>) goes outside the content-box<\/code> of the range is an option in some cases, but not always.<\/p>\n

    For the height<\/code>, Firefox behaves in a similar manner it did for the width<\/code>. The track expands or shrinks vertically to the height<\/code> we set without affecting the parent slider and always staying middle aligned to it vertically.<\/p>\n

    \"Gif
    Explicitly setting a height<\/code> on the track changes the height<\/code> of the track in Firefox, but not that of the parent slider.<\/figcaption><\/figure>\n

    The default value for this height<\/code> with no styles set on the actual input<\/code> or track is .2em<\/code>.<\/p>\n

    \"Gif
    Changing the font-size<\/code> on the track changes its computed height<\/code> in Firefox.<\/figcaption><\/figure>\n

    Unlike in the case of the width<\/code>, Chrome allows the track to take the height<\/code> we set and, if we’re not using a %<\/code> value here, it also makes the content-box<\/code> of the parent slider expand or shrink such that the border-box<\/code> of the track perfectly fits in it. When using a %<\/code> value, the actual slider and the track are middle aligned vertically.<\/p>\n

    \"Gif
    Explicitly setting a height<\/code> on the track in %<\/code> changes the height<\/code> of the track in Chrome, but not that of the parent slider. Using other units, the actual range input<\/code> expands or shrinks vertically such that the track perfectly fits inside.<\/figcaption><\/figure>\n

    The computed value we get for the height<\/code> without setting any custom styles is the same as for the slider and doesn’t change with the font-size<\/code>.<\/p>\n

    \"Gif
    Changing the font-size<\/code> on the track doesn’t change its computed height<\/code> in Chrome.<\/figcaption><\/figure>\n

    What about Edge? Well, we can change the height<\/code> of the track independently of that of the parent slider and they both stay middle aligned vertically, but all of this is only as long as the track height<\/code> we set is smaller than the initial height<\/code> of the actual input<\/code>. Above that, the track’s computed height<\/code> is always equal to that of the parent range.<\/p>\n

    \"Gif
    Explicitly setting a height<\/code> on the track in Edge doesn’t change the height<\/code> of the parent slider and the two are middle aligned. However, the height<\/code> of the track is limited by that of the actual input<\/code>.<\/figcaption><\/figure>\n

    The initial track height is 11px<\/code> and this value doesn’t depend on the font-size<\/code> or on the viewport.<\/p>\n

    \"Gif
    Changing the font-size<\/code> on the track doesn’t change its computed height<\/code> in Edge.<\/figcaption><\/figure>\n

    Moving on to something less mindbending, we have box-sizing<\/code>. This is border-box<\/code> in Chrome and content-box<\/code> in Edge and Firefox so, if we’re going to have a non-zero border<\/code> or padding<\/code>, then box-sizing<\/code> is a property we need to explicitly set in order to even things out.<\/p>\n

    \"Comparative
    The box-sizing<\/code> of the track, comparative look at all three browsers (from top to bottom: Chrome, Firefox, Edge).<\/figcaption><\/figure>\n

    The default track margin<\/code> and padding<\/code> are both 0<\/code> in all three browsers – finally, an oasis of consistency!<\/p>\n

    \"Comparative
    The box-sizing<\/code> of the track, comparative look at all three browsers (from top to bottom: Chrome, Firefox, Edge).<\/figcaption><\/figure>\n

    The values for the color<\/code> property can be inherited from the parent slider in all three browsers.<\/p>\n

    \"Comparative
    The color<\/code> of the track, comparative look at Chrome (top) and Firefox (bottom).<\/figcaption><\/figure>\n

    Even so, Edge is the odd one here, changing it to white<\/code>, though setting it to initial<\/code> changes it to black<\/code>, which is the value we have for the actual input<\/code>.<\/p>\n

    \"Resetting
    Resetting the color<\/code> to initial<\/code> in Edge.<\/figcaption><\/figure>\n

    Setting -webkit-appearance: none<\/code> on the actual input<\/code> in Edge makes the computed value of the color<\/code> on the track transparent<\/code> (if we haven’t explicitly set a color<\/code> value ourselves). Also, once we add a background<\/code> on the track, the computed track color<\/code> suddenly changes to black<\/code>.<\/p>\n

    \"Adding
    Unexpected consequence of adding a background<\/code> track in Edge.<\/figcaption><\/figure>\n

    To a certain extent, the ability to inherit the color<\/code> property is useful for theming, though inheriting custom properties can do a lot more here. For example, consider we want to use a silver for secondary things and an orange for what we want highlighted. We can define two CSS variables on the body and then use them across the page, even inside our range inputs.<\/p>\n

    body {\r\n  --fading: #bbb;\r\n  --impact: #f90\r\n}\r\n\r\nh2 { border-bottom: solid .125em var(--impact) }\r\n\r\nh6 { color: var(--fading) }\r\n\r\n[type='range']:focus { box-shadow: 0 0 2px var(--impact) }\r\n\r\n@mixin track() { background: var(--fading) }\r\n\r\n@mixin thumb() { background: var(--impact) }<\/code><\/pre>\n

    Sadly, while this works in Chrome and Firefox, Edge doesn’t currently allow custom properties on the range input<\/code>to be inherited down to its components.<\/p>\n

    \"Screenshots
    Expected result (left) vs. result in Edge (right), where no track or thumb show up (live demo<\/a>).<\/figcaption><\/figure>\n

    By default, there is no border<\/code> on the track in Chrome or Firefox (border-width<\/code> is 0<\/code> and border-style<\/code> is none<\/code>).<\/p>\n

    \"Comparative
    The border<\/code> of the track, comparative look at Chrome (top) and Firefox (bottom).<\/figcaption><\/figure>\n

    Edge has no border<\/code> on the track if we have no background<\/code> set on the actual input and no background<\/code> set on the track itself. However, once that changes, we get a thin (1px<\/code>) black<\/code> track border<\/code>.<\/p>\n

    \"Adding
    Another unexpected consequence of adding a track or parent slider background<\/code> in Edge.<\/figcaption><\/figure>\n

    The default background-color<\/code> is shown to be inherited as white, but then somehow we get a computed value of rgba(0,0,0,0)<\/code> (transparent<\/code>) in Chrome (both before and after -webkit-appearance: none<\/code>). This also makes me wonder how come we can see the track before, since there’s no background-color<\/code> or background-image<\/code> to give us anything visible. Firefox gives us a computed value of rgb(153,153,153)<\/code> (#999<\/code>) and Edge transparent<\/code> (even though we might initially think it’s some kind of silver, that is not the background<\/code> of the ::-ms-track<\/code> element – more on that a bit later).<\/p>\n

    \"Comparative
    The background-color<\/code> of the track, comparative look at all three browsers (from top to bottom: Chrome, Firefox, Edge).<\/figcaption><\/figure>\n

    The range thumb component<\/h4>\n

    Ready for the most annoying inconsistency yet? The thumb moves<\/a> within the limits of the track’s content-box<\/code> in Chrome and within the limits of the actual input<\/code>‘s content-box<\/code> in Firefox and Edge, even when we make the track longer or shorter than the input<\/code> (Chrome doesn’t allow this, forcing the track’s border-box<\/code> to fit the slider’s content-box<\/code> horizontally).<\/p>\n

    The way Chrome behaves is illustrated below:<\/p>\n

    \"Chrome
    Recording of the thumb motion in Chrome from one end of the slider to the other.<\/figcaption><\/figure>\n

    The padding is transparent, while the content-box and the border are semitransparent. We’ve used orange for the actual slider, red for the track and purple for the thumb.<\/p>\n

    For Firefox, things are a bit different:<\/p>\n

    \"Firefox
    Recording of the thumb motion in Firefox from one end of the slider to the other (the three cases from top to bottom: the border-box<\/code> of the track perfectly fits the content-box<\/code> of the slider horizontally, it’s longer and it’s shorter).<\/figcaption><\/figure>\n

    In Chrome, the thumb is the child of the track, while in Firefox it’s its sibling, so, looking at it this way, it makes sense that Chrome would move the thumb within the limits of the track’s content-box<\/code> and Firefox would move it within the limits of the slider’s content-box<\/code>. However, the thumb is inside the track in Edge too and it still moves within the limits of the slider’s content-box<\/code>.<\/p>\n

    \"Animated
    Recording of the thumb motion in Edge from one end of the slider to the other (the three cases from top to bottom: the border-box<\/code> of the track perfectly fits the content-box<\/code> of the slider horizontally, it’s longer and it’s shorter).<\/figcaption><\/figure>\n

    While this looks very strange at first, it’s because Edge forces the position<\/code> of the track to static<\/code> and we cannot change that, even if we set it to relative<\/code> with !important<\/code>.<\/p>\n

    \"Animated
    Trying (and failing) to change the value of the position<\/code> property on the track in Edge.<\/figcaption><\/figure>\n

    This means we may style our slider exactly the same for all browsers, but if its content-box<\/code> doesn’t coincide to that of its track horizontally (so if we have a non-zero lateral padding<\/code> or border<\/code> on the track), it won’t move within the same limits in all browsers.<\/p>\n

    Furthermore, if we scale the track horizontally, then Chrome and Firefox behave as they did before, the thumb moving within the limits of the now scaled track’s content-box<\/code> in Chrome and within the limits of the actual input<\/code>‘s content-box<\/code> in Firefox. However, Edge makes the thumb move within an interval whose width equals that of the track’s border-box<\/code>, but starts from the left limit of the track’s padding-box<\/code>, which is probably explained by the fact that the transform<\/code> property creates a stacking context<\/a>.<\/p>\n

    \"Edge
    Recording of the thumb motion in Edge when the track is scaled horizontally.<\/figcaption><\/figure>\n

    Vertically, the thumb is middle-aligned to the track in Firefox, seemingly middle-aligned in Edge, though I’ve been getting very confusing different results over multiple tests of the same situation, and the top of its border-box<\/code> is aligned to the top of the track’s content-box<\/code> in Chrome once we’ve set -webkit-appearance: none<\/code> on the actual input<\/code> and on the thumb so that we can style the slider.<\/p>\n

    While the Chrome decision seems weird at first, is annoying in most cases and lately has even contributed to breaking things in… Edge (but more about that in a moment), there is some logic behind it. By default, the height<\/code> of the track in Chrome is determined by that of the thumb and if we look at things this way, the top alignment doesn’t seem like complete insanity anymore.<\/p>\n

    However, we often want a thumb that’s bigger than the track’s height and is middle aligned to the track. We can correct the Chrome alignment with margin-top<\/code> in the styles we set on the ::-webkit-slider-thumb<\/code> pseudo.<\/p>\n

    Unfortunately, this way we’re breaking the vertical alignment in Edge. This is because Edge now applies the styles set via ::-webkit-slider-thumb<\/code> as well. At least we have the option of resetting margin-top<\/code> to 0<\/code> in the styles we set on ::-ms-thumb<\/code>. The demo below shows a very simple example of this in action.<\/p>\n

    See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n

    Just like in the case of the track, the value of the box-sizing<\/code> property is border-box<\/code> in Chrome and content-box<\/code> in Edge and Firefox, so, for consistent results across browsers, we need to set it explicitly if we want to have a non-zero border<\/code> or padding<\/code> on the thumb.<\/p>\n

    The margin<\/code> and padding<\/code> are both 0<\/code> by default in all three browsers.<\/p>\n

    After setting -webkit-appearance: none<\/code> on both the slider and the thumb (setting it on just one of the two doesn’t change anything), the dimensions of the thumb are reset from 10x21<\/code> (dimensions that don’t depend on the font-size<\/code>) to 129x0<\/code> in Chrome. The height<\/code> of the track and actual slider also get reset to 0<\/code>, since they depend on that of their content (the thumb inside, whose height<\/code> has become 0<\/code>).<\/p>\n

    \"Animated
    The thumb box model in Chrome.<\/figcaption><\/figure>\n

    This is also why explicitly setting a height<\/code> on the thumb makes the track take the same height<\/code>.<\/p>\n

    According to Chrome DevTools, there is no border<\/code> in either case, even though, before setting -webkit-appearance: none<\/code>, it sure looks like there is one.<\/p>\n

    \"Screenshot.
    How the slider looks in Chrome before setting -webkit-appearance: none<\/code>.<\/figcaption><\/figure>\n

    If that’s not a border<\/code>, it might be an outline<\/code> or a box-shadow<\/code> with no blur and a positive spread. But, according to Chrome DevTools, we don’t have an outline<\/code>, nor box-shadow<\/code> on the thumb.<\/p>\n

    \"Screenshot.
    Computed values for outline<\/code> and box-shadow<\/code> in Chrome DevTools.<\/figcaption><\/figure>\n

    Setting -webkit-appearance: none<\/code> in Edge makes the thumb dimensions go from 11x11<\/code> (values that don’t depend on the font-size<\/code>) to 0x0<\/code>. Explicitly setting a height<\/code> on the thumb makes the track take the initial height<\/code> (11px<\/code>).<\/p>\n

    \"Animated
    The thumb box model in Edge.<\/figcaption><\/figure>\n

    In Edge, there’s initially no border<\/code> on the thumb. However, after setting a background<\/code> on either the actual range input<\/code> or any of its components, we suddenly get a solid 1px white<\/code> lateral one (left and right, but not top and bottom), which visually turns to black<\/code> in the :active<\/code> state (even though Edge DevTools doesn’t seem to notice that). Setting -webkit-appearance: none<\/code> removes the border-width<\/code>.<\/p>\n

    \"Animated
    The thumb border<\/code> in Edge.<\/figcaption><\/figure>\n

    In Firefox, without setting a property like background<\/code> on the range input<\/code> or its components, the dimensions of the thumb are 1.666x3.333<\/code> and, in this case, they don’t change with the font-size<\/code>. However, if we set something like background: transparent<\/code> on the slider (or any background<\/code> value on its components), then both the width<\/code> and height<\/code> of the thumb become 1em<\/code>.<\/p>\n

    \"Animated
    The thumb box model in Firefox.<\/figcaption><\/figure>\n

    In Firefox, if we are to believe what we see in DevTools, we initially have a solid thick grey (rgb(153, 153, 153)<\/code>) border<\/code>.<\/p>\n

    \"Screenshot.
    The thumb border<\/code> in Firefox DevTools.<\/figcaption><\/figure>\n

    Visually however, I can’t spot this thick grey border<\/code> anywhere.<\/p>\n

    \"Screenshot
    How the slider looks initially in Firefox, before setting a background on it or on any of its components.<\/figcaption><\/figure>\n

    After setting a background<\/code> on the actual range input<\/code> or one of its components, the thumb border<\/code> actually becomes visually detectable and it seems to be .1em<\/code>.<\/p>\n

    \"Animated
    The thumb border<\/code> in Firefox.<\/figcaption><\/figure>\n

    In Chrome and in Edge, the border-radius<\/code> is always 0<\/code>.<\/p>\n

    \"Screenshots.
    The thumb border-radius<\/code> in Chrome (top) and Edge (bottom).<\/figcaption><\/figure>\n

    In Firefox however, we have a .5em<\/code> value for this property, both before and after setting a background<\/code> on the range input<\/code> or on its components, even though the initial shape of the thumb doesn’t look like a rectangle with rounded corners.<\/p>\n

    \"Animated
    The thumb border-radius<\/code> in Firefox.<\/figcaption><\/figure>\n

    The strange initial shape of the thumb in Firefox has made me wonder whether it doesn’t have a clip-path<\/code> set, but that’s not the case according to DevTools.<\/p>\n

    \"Screenshot.
    The thumb clip-path<\/code> in Firefox.<\/figcaption><\/figure>\n

    More likely, the thumb shape is due to the -moz-field<\/code> setting, though, at least on Windows 10, this doesn’t make it look like every other slider.<\/p>\n

    \"Screenshots.
    Initial appearance of slider in Firefox vs. appearance of a native Windows 10 slider.<\/figcaption><\/figure>\n

    The thumb’s background-color<\/code> is reported as being rgba(0, 0, 0, 0)<\/code> (transparent<\/code>) by Chrome DevTools, even though it looks grey before setting -webkit-appearance: none<\/code>. We also don’t seem to have a background-image<\/code> that could explain the gradient or the lines on the thumb before setting -webkit-appearance: none<\/code>. Firefox DevTools reports it as being rgb(240, 240, 240)<\/code>, even though it looks blue as long as we don’t have a background<\/code> explicitly set on the actual range input<\/code> or on any of its components.<\/p>\n

    \"Screenshots.
    The thumb background-color<\/code> in Chrome (top) and Firefox (bottom).<\/figcaption><\/figure>\n

    In Edge, the background-color<\/code> is rgb(33, 33, 33)<\/code> before setting -webkit-appearance: none<\/code> and transparent<\/code> after.<\/p>\n

    \"Animated
    The thumb background-color<\/code> in Edge.<\/figcaption><\/figure>\n

    The range progress (fill) component<\/h4>\n

    We only have dedicated pseudo-elements for this in Firefox (::-moz-range-progress<\/code>) and in Edge (::-ms-fill-lower<\/code>). Note that this element is a sibling of the track in Firefox and a descendant in Edge. This means that it’s sized relative to the actual input<\/code> in Firefox, but relative to the track in Edge.<\/p>\n

    In order to better understand this, consider that the track’s border-box<\/code> perfectly fits horizontally within the slider’s content-box<\/code> and that the track has both a border<\/code> and a padding<\/code>.<\/p>\n

    In Firefox, the left limit of the border-box<\/code> of the progress component always coincides with the left limit of the slider’s content-box<\/code>. When the current slider value is its minimum value, the right limit of the border-box<\/code> of our progress also coincides with the left limit of the slider’s content-box<\/code>. When the current slider value is its maximum value, the right limit of the border-box<\/code> of our progress coincides with the right limit of the slider’s content-box<\/code>.<\/p>\n

    This means the width<\/code> of the border-box<\/code> of our progress goes from 0<\/code> to the width<\/code> of the slider’s content-box<\/code>. In general, when the thumb is at x%<\/code> of the distance between the two limit value, the width<\/code> of the border-box<\/code> for our progress is x%<\/code> of that of the slider’s content-box<\/code>.<\/p>\n

    This is shown in the recording below. The padding<\/code> area is always transparent, while the border<\/code> area and content-box<\/code> are semitransparent (orange for the actual input<\/code>, red for the track, grey for the progress and purple for the thumb).<\/p>\n

    \"Animated
    How the width<\/code> of the ::-moz-range-progress<\/code> component changes in Firefox.<\/figcaption><\/figure>\n

    In Edge however, the left limit of the fill’s border-box<\/code> always coincides with the left limit of the track’s content-box<\/code> while the right limit of the fill’s border-box<\/code> always coincides with the vertical line that splits the thumb’s border-box<\/code> into two equal halves. This means that when the current slider value is its minimum value, the right limit of the fill’s border-box<\/code> is half the thumb’s border-box<\/code> to the right of the left limit of the track’s content-box<\/code>. And when the current slider value is its maximum value, the right limit of the fill’s border-box<\/code> is half the thumb’s border-box<\/code> to the left of the right limit of the track’s content-box<\/code>.<\/p>\n

    This means the width<\/code> of the border-box<\/code> of our progress goes from half the width<\/code> of the thumb’s border-box<\/code> minus the track’s left border<\/code> and padding<\/code> to the width<\/code> of the track’s content-box<\/code> plus the track’s right padding<\/code> and border<\/code> minus half the width<\/code> of the thumb’s border-box<\/code>. In general, when the thumb is at x%<\/code> of the distance between the two limit value, the width<\/code> of the border-box<\/code> for our progress is its minimum width<\/code> plus x%<\/code> of the difference between its maximum and its minimum width<\/code>.<\/p>\n

    This is all illustrated by the following recording of this live demo<\/a> you can play with:<\/p>\n

    \"Animated
    How the width<\/code> of the ::-ms-fill-lower<\/code> component changes in Edge.<\/figcaption><\/figure>\n

    While the description of the Edge approach above might make it seem more complicated, I’ve come to the conclusion that this is the best way to vary the width of this component as the Firefox approach may cause some issues.<\/p>\n

    For example, consider the case when we have no border<\/code> or padding<\/code> on the track for cross browser consistency and the height<\/code> of the both the fill’s and thumb’s border-box<\/code> equal to that of the track. Furthermore, the thumb is a disc (border-radius: 50%<\/code>).<\/p>\n

    In Edge, all is fine:<\/p>\n

    \"Animated
    How our example works in Edge.<\/figcaption><\/figure>\n

    But in Firefox, things look awkward (live demo<\/a>):<\/p>\n

    \"Animated
    How our example works in Firefox.<\/figcaption><\/figure>\n

    The good news is that we don’t have other annoying and hard to get around inconsistencies in the case of this component.<\/p>\n

    box-sizing<\/code> has the same computed value in both browsers – content-box<\/code>.<\/p>\n

    \"Screenshot.
    The computed value for box-sizing<\/code> in the case of the progress (fill) component: Firefox (top) and Edge (bottom).<\/figcaption><\/figure>\n

    In Firefox, the height<\/code> of the progress is .2em<\/code>, while the padding<\/code>, border<\/code> and margin<\/code> are all 0<\/code>.<\/p>\n

    \"Animated
    The height<\/code> of the progress in Firefox.<\/figcaption><\/figure>\n

    In Edge, the fill’s height<\/code> is equal to that of the track’s content-box<\/code>, with the padding<\/code>, border<\/code> and margin<\/code> all being 0<\/code>, just like in Firefox.<\/p>\n

    \"Animated
    The height<\/code> of the fill in Edge.<\/figcaption><\/figure>\n

    Initially, the background<\/code> of this element is rgba(0, 0, 0, 0)<\/code> (transparent<\/code>, which is why we don’t see it at first) in Firefox and rgb(0, 120, 115)<\/code> in Edge.<\/p>\n

    \"Screenshot.
    The background-color<\/code> of the progress (fill) in Firefox (top) and Edge (bottom).<\/figcaption><\/figure>\n

    In both cases, the computed value of the color<\/code> property is rgb(0, 0, 0)<\/code> (solid black<\/code>).<\/p>\n

    \"Screenshot.
    The computed value for color<\/code> in the case of the progress (fill) component: Firefox (top) and Edge (bottom).<\/figcaption><\/figure>\n

    WebKit browsers don’t provide such a component and, since we don’t have a way of accessing and using a track’s ::before<\/code> or ::after<\/code> pseudos anymore, our only option of emulating this remains layering an extra, non-repeating background<\/code> on top of the track’s existing one for these browsers and making the size of this extra layer along the x<\/code> axis depend depend on the current value of the range input<\/code>.<\/p>\n

    The simplest way of doing this nowadays is by using a current value --val<\/code> CSS variable, which holds the slider’s current value. We update this variable every time the slider’s value changes and we make the background-size<\/code> of this top layer a calc()<\/code> value depending on --val<\/code>. This way, we don’t have to recompute anything when the value of the range input<\/code> changes – our calc()<\/code> value is dynamic, so updating the --val<\/code> variable is enough (not just for this background-size<\/code>, but also for other styles that may depend on it as well).<\/p>\n

    See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n

    Also doing this for Firefox is an option if the way ::-moz-range-progress<\/code> increases doesn’t look good for our particular use case.<\/p>\n

    Edge also provides a ::-ms-fill-upper<\/code> which is basically the complementary of the lower one and it’s the silver background<\/code> of this pseudo-element that we initially see to the right of the thumb, not that of the track (the track is transparent<\/code>).<\/p>\n

    Tick marks and labels<\/h4>\n

    Edge is the only browser that shows tick marks by default. They’re shown on the track, delimiting two, five, ten, twenty sections, the exact number depending initially on the track width<\/code>. The only style we can change for these tick marks is the color<\/code> property as this is inherited from the track (so setting color: transparent<\/code> on the track removes the initial tick marks in Edge).<\/p>\n

    \"Screenshot.
    The structure that generates the initial tick marks on the track in Edge.<\/figcaption><\/figure>\n

    The spec says<\/a> that tick marks and labels can be added by linking a datalist<\/code> element, for whose option<\/code> children we may specify a label<\/code> attribute if we want that particular tick mark to also have a label.<\/p>\n

    Unfortunately, though not at all surprising anymore at this point, browsers have a mind of their own here too. Firefox doesn’t show anything – no tick marks, no labels. Chrome shows the tick marks, but only allows us to control their position along the slider with the option<\/code> values. It doesn’t allow us to style them in any way and it doesn’t show any labels.<\/p>\n

    \"Screenshot.
    Tick marks in Chrome.<\/figcaption><\/figure>\n

    Also, setting -webkit-appearance: none<\/code> on the actual slider (which is something that we need to to in order to be able to style it) makes these tick marks disappear.<\/p>\n

    Edge joins the club and doesn’t show any labels either and it doesn’t allow much control over the look of the ticks either. While adding the datalist<\/code> allows us to control which tick marks are shown where on the track, we cannot style them beyond changing the color<\/code> property on the track component.<\/p>\n

    \"Screenshot.
    Tick marks in Edge.<\/figcaption><\/figure>\n

    In Edge, we also have ::-ms-ticks-before<\/code> and ::-ms-ticks-after<\/code> pseudo-elements. These are pretty much what they sound like – tick marks before and after the track. However, I’m having a hard time understanding how they really work.<\/p>\n

    They’re hidden by display: none<\/code>, so changing this property to block<\/code> makes them visible if we also explicitly set<\/em> a slider height<\/code>, even though doing this does not change their own height<\/code>.<\/p>\n

    \"Animated
    How to make tick marks crested by ::-ms-ticks-after<\/code> visible in Edge.<\/figcaption><\/figure>\n

    Beyond that, we can set properties like margin<\/code>, padding<\/code>, height<\/code>, background<\/code>, color<\/code> in order to control their look. However, I have no idea how to control the thickness of individual ticks, how to give individual ticks gradient backgrounds or how to make some of them major and some minor.<\/p>\n

    So, at the end of the day, our best option if we want a nice cross-browser result remains using repeating-linear-gradient<\/code><\/a> for the ticks and the label<\/code> element for the values corresponding to these ticks.<\/p>\n

    See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n

    Tooltip\/ current value display<\/h4>\n

    Edge is the only browser that provides a tooltip via ::-ms-tooltip<\/code>, but this doesn’t show up in the DOM, cannot really be styled (we can only choose to hide it by setting display: none<\/code> on it) and can only display integer values, so it’s completely useless for a range input<\/code> between let’s say .1<\/code> and .4<\/code> – all the values it displays are 0<\/code>!<\/p>\n

    \"Animated
    ::-ms-tooltip<\/code> when range limits are both subunitary.<\/figcaption><\/figure>\n

    So our best bet is to just hide this and use the output<\/code> element<\/a> for all browsers, again taking advantage of the possibility of storing the current slider value into a --val<\/code> variable and then using a calc()<\/code> value depending on this variable for the position.<\/p>\n

    See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n

    Orientation<\/h3>\n

    The good news is that every browser allows us to create vertical sliders. The bad news is, as you may have guessed… every browser provides a different way of doing this, none of which is the one presented in the spec (setting a width<\/code> smaller than the height<\/code> on the range input<\/code>). WebKit browsers have opted for -webkit-appearance: slider-vertical<\/code>, Edge for writing-mode: bt-lr<\/code>, while Firefox controls this via an orient<\/code> attribute with a value of 'vertical'<\/code>.<\/p>\n

    The really bad news is that, for WebKit browsers, making a slider vertical this way leaves us unable to set any custom styles on it (as setting custom styles requires a value of none<\/code> for -webkit-appearance<\/code>).<\/p>\n

    Our best option is to just style our range input<\/code> as a horizontal one and then rotate it with a CSS transform<\/code>.<\/p>\n

    See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"

    You may have already seen a bunch of tutorials on how to style the range input. While this is another article on that topic, it’s not about how to get any specific visual result. Instead, it dives into browser inconsistencies, detailing what each does to display that slider on the screen. Understanding this is important […]<\/p>\n","protected":false},"author":225572,"featured_media":262680,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4],"tags":[1051,478],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2017\/11\/structure_firefox-an.png?fit=1000%2C741&ssl=1","jetpack-related-posts":[],"featured_media_src_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2017\/11\/structure_firefox-an.png?fit=1000%2C741&ssl=1","_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/262598"}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/225572"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=262598"}],"version-history":[{"count":105,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/262598\/revisions"}],"predecessor-version":[{"id":264168,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/262598\/revisions\/264168"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media\/262680"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=262598"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=262598"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=262598"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}