In this article, you’ll find out how to use the HTML disabled
boolean attribute, toggle it with JavaScript and style disabled form controls.
disabled
boolean attribute
disabled
state with JS
disabled
form controls
disabled
boolean attributeAccording to WHATWG, the HTML disabled
attribute is supported by a limited group of HTML elements and by the newly introduced form-associated custom elements:
button
fieldset
optgroup
option
select
textarea
input
In this article we’ll be focusing on the basic HTML elements only, so here’s a checkbox input which has a disabled
attribute:
Note that setting a value for the disabled
attribute is not really required, due to its boolean logic. Therefore, considering the presence of a boolean attribute on an element, all the below values are redundant and the outcome is a disabled
behavior anyway:
disabled="disabled"
disabled="true"
disabled="false"
disabled="whatever"
The HTML fieldset
element is used to group several controls within a web form. If the boolean disabled
attribute is set on the fieldset
, then all the form controls contained within will become disabled too.
Here’s an example with both of the form controls being disabled due to being wrapped by a disabled fieldset
element.
disabled
!= readonly
Comparing to the readonly
form controls, the disabled
ones are not submitted within a form, therefore they are also ignored when it comes to form
validation. Also, the disabled
form controls are not focusable either.
aria-disabled
attributeIf you can use a native HTML element or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so.
from W3C
When using an HTML element, such as a form control, which natively supports the disabled
boolean attribute, you don’t need the aria-disabled
attribute.
Steve Faulkner wrote a good piece on the disabled/aria-disabled attributes so you should go check it out!
disabled
state with JSYou can take advantage of the fact that the .disabled
property returns a boolean value so you can toggle it easily using the following:
Also, besides the classic removeAttribute()
and setAttribute()
methods, you can use the toggleAttribute()
method to toggle the disabled
attribute or any other boolean attribute. Although the browser support is not perfect, this might come in handy:
Speaking of disabled elements and JavaScript, Jake Archibald wrote an interesting piece on firing events on disabled form controls, in which he argues about the need to use pointer-events: none
on all the :disabled
elements.
With better browser support for the :is()
(formerly :any()
or :matches()
, as @SelenIT2 pointed out) CSS pseudo-class, here’s how we could write a bulletproof CSS rule, to prevent interaction and event issues on the disabled form controls:
The fieldset
element is excluded in the above rule in order to avoid breaking other elements or title
attributes wrapped within it.
disabled
form controlsThere are two ways to select a disabled element using CSS:
The old [disabled]
attribute selector can be used for any HTML element user that has a disabled
attribute, and it doesn’t really have to be a form control element.
The :disabled
pseudo-class, introduced in Selectors Level 3, is the preferred method to select a disabled element, due to the fact it matches HTML elements that support the disabled
attribute only.
Links are not button
s, neither div
s, span
s or whatever. Still, an a
element can act as a placeholder link when it’s used without its href
attribute.
If the
a
element has no href attribute, then the element represents a placeholder for where a link might otherwise have been placed.From WHATWG
We know that the :disabled
CSS pseudo-class only applies to form controls that natively support a disabled
attribute and the a
element is not among them.
Therefore, the following CSS rule contains both the [disabled]
attribute selector and the .disabled
class selector. You know, just in case you want, need, or have to use <a disabled>...</a>
instead of <a class="disabled">...</a>
in a certain situation.
If you’re wondering why would you even disable link elements, there is a scenario I’m having in mind and I’m sure you also did stumble upon this before:
Let’s say you have an active item within a navigation, showing it’s the active URL in that navigation. Now, besides the active styles applied to it, you might also want to prevent the user clicking and refreshing that already active page he’s on.
disabled
stylesIn case you’re wondering where all those default disabled styles come from, here’s a list with the most popular User Agent styles, feel free to dive in:
disabled
attribute on a fieldset
.pointer-events: none
declaration to a link, in an attempt to disable it, you should also think of applying tabindex="-1"
in order to take it out of the tab order.[disabled]
attribute selector in favor of the :disabled
pseudo-class. Perhaps needing IE6 - IE8 support and that’s definitely not a good reason.disabled
attribute, the aria-disabled
, when set as an attribute, does require a value of either true
or false
.aria-disabled="false"
is set on a form control along with the disabled
attribute, then the latter has greater specificity and the aria-disabled
attribute gets ignored.img
and input
, are part of the void elements set as well.
With that in mind, I thought about a Venn diagram that does the job perfectly when it comes to represent and visualize the intersection between these two sets of HTML replaced and void elements.
According to W3C, an HTML replaced element is an element whose content is outside the scope of the CSS formatting model. An example is the HTML img
element, whose content is replaced by the image that its src
attribute designates.
Oh, and the img
element is one of the HTML void elements too.
Neither CSS nor HTML standards didn’t define before which elements are replaced. So back in 2012, after gathering input from some really awesome people, I did wrote about CSS content on HTML replaced elements, namely how the ::before
and ::after
pseudo-elements should work on HTML replaced elements.
Here’s the list of HTML elements that can be replaced elements, according to the WHATWG:
audio
canvas
embed
iframe
img
input
object
video
Objects inserted using the CSS content property are anonymous replaced elements. They are “anonymous” because they don’t exist in the HTML markup.
from MDN
I did stumble upon this while writing on how to get the current DOM node in browser’s console but didn’t actually know they are called anonymous replaced elements. So, you can run $0
on CSS pseudo-elements in the DOM, because the ::before
and ::after
pseudo-elements are displayed in browsers’ elements tree.
The object-fit
and object-position
are two CSS properties that apply only to the HTML replaced elements:
object-fit
specifies how the contents of an HTML replaced element should be fitted to the box established by its used height and width.object-position
determines the alignment of the replaced element inside its box.The default size for some of the HTML replaced elements, like iframe
or object
, is 300
pixels wide and 150
pixels tall.
img
is not a replaced elementEven if the img
is considered and therefore listed as a replaced element, when the img
is rendered as its alt
attribute text, that img
no longer acts like a replaced element.
Therefore, it is possible to use CSS pseudo-elements in order to style the img
element when its source image has failed to load. Here’s an article on how to style broken images, by Ire Aderinokun.
input
sWithin the WHATWG table of contents, the form controls are listed under the non-replaced elements. The main reason the input
element can be considered a replaced element is due to the fact that input
s with image
type attributes are replaced elements similar to img
.
This means that using ::before
and ::after
pseudo-elements on <input type="checkbox/radio">
is allowed, according to the current standards.
To better explain HTML void elements, we should point out first what tags are. When it comes to the HTML anatomy, first of all, tags are not elements, as this is a pretty common misunderstanding. The tags are meant to delimit the start and end of elements in the markup.
The HTML void elements don’t have a proper end tag, therefore they can’t have any kind of content between the start tag and the end tag.
Void elements only have a start tag e.g. <input type="url">
.
Here’s the list of void elements, according to WHATWG:
area
base
br
col
embed
hr
img
input
link
meta
param
source
track
wbr
It often happens to see void elements in the wild with a closing forward slash like <br/>
or even with an extra space e.g. <br />
, which is specific to the XHTML syntax. For better compatibility with XHTML, the slash is allowed on void elements by the HTML specification, therefore the document passes the markup validation.
As a side note, depending on the type of the HTML element here’s what the forward slash does on <foo/>
:
foo
is a void element, then the /
gets ignored.<defs/>
within an inline SVG, then the self-closing syntax is valid.<foo>
. Usually, this leads to a mess in your markup as the siblings are now considered children of the foo
element.Here’s what I noticed, after lurking through W3C, WHATWG and MDN docs, old issues and forgotten corners of the web:
The void elements are often called empty elements, single elements, stand-alone elements, unpaired elements or singleton elements. Yes, singleton, the design pattern, because I guess that’s what happens when Java programmers start writing HTML.
Both W3C and MDN list the HTML elements as if they are start tags e.g. U+003C
(<
), tag name (element’s name) and U+003E
(>
), while WHATWG seems to do it the right way.
Within the MDN docs, the void elements are referred solely as empty elements, that cannot have any child nodes.
It seems that Prettier and ESLint are still fighting over void elements, whether to close or not to close them.
While WHATWG says that audio
, canvas
, embed
, iframe
, img
, input
, object
, and video
can be replaced elements, MDN list only iframe
, video
, embed
, img
as typical replaced elements while option
, audio
, canvas
, object
and applet
are treated as replaced elements only in specific cases.
I stumbled upon this issue on the need to add an exhaustive list of replaced elements to the specs. That happened eventually, it just took a bit longer.
On the W3C vs WHATWG matter, hopefully, things are going in the right direction now, as in 2019, W3C and the WHATWG have signed an agreement to collaborate on the development of a single version of the HTML and DOM specifications.
When in doubt over one or the other, either it’s a replaced or a void element, I hope the above Venn diagram will come in handy.
Oh, and always validate your markup, it does miracles for your body
!
prefers-color-scheme
media feature.
A favorites icon, also known as a favicon, is a tiny icon associated with a particular web site or web page that is displayed usually in browser’s address bar and bookmarks menu.
The favicon is used to improve the user experience and enforce a brand’s consistency. When a familiar favicon is seen in the browser’s address bar, for example, it helps users to know they are in the right place. This is how phishing in the browser usually succeeds but that’s a completely different story.
Here are the image formats you can use to add a favicon to your website. Spoiler alert: there is no one-size-and-format that fits in all the browsers. There would have been too easy!
In this article, we’ll be focusing on the latter approach that is based on using the Scalable Vector Graphics (SVG), as it teams up perfectly with the CSS prefers-color-scheme
media feature.
We don’t know for sure yet why most developers prefer to use dark themes in general but some say it’s comfortable on the eyes while others find it more exciting. Also, there’s the category below:
― Why do programmers prefer dark mode?
― Cause light attracts bugs.
from r/Jokes
You can enable CSS theme mode detection with CSS prefers-color-scheme
media feature, in order to add an alternative look and feel to your website with custom CSS rules:
According to MDN, the Window’s matchMedia()
method returns an object that represents the result of the specified media query string.
The dark mode or dark theme has made its way to the main headlights for some time, so here’s how to detect the darkness with JavaScript:
Although the above is a possible and working solution for switching the favicon in the HTML, I wouldn’t recommend it, as now you can do that without JavaScript at all.
First, add the SVG favicon to your HTML <head>
section:
Regarding the SVG favicon.svg
’s inner content, below is a rough example of an SVG rectangle with rounded corners, which has a different color, depending on the active theme. The detection is made using the above CSS prefers-color-scheme
media feature.
Considering the current browser support for the SVG favicon, a fallback is required. In this case, we serve the PNG format when the browser fails to accept SVG as a favicon.
If the user agent tries to use an icon but that icon is determined, upon closer examination, to in fact be inappropriate (e.g. because it uses an unsupported format), then the user agent must try the next-most-appropriate icon as determined by the attributes.
from WHATWG docs
The common approach when it comes to older browsers that support neither the PNG favicon format is to keep a favicon.ico
file in the root. Careful not to <link>
to it within the <head>
section at all because doing that will result in browsers picking the favicon.ico
as the default.
With that being said, after testing this in all the existing modern browsers, here is the order the browsers will look for the favicon, with the code above:
Yes, lots of browsers, because we have to love them all!
You might want to read more on SVG, favicons and CSS media features:
]]>In this article, you’ll learn how to get the current DOM node using $0
in the browser’s console and what to expect when you run it on the CSS pseudo-elements displayed in the elements tree.
$0
returns the current DOM node. The same $0
on CSS pseudo-elements in the DOM returns inconsistent results across different browsers.$r
returns the current React component.$vm0
returns the current Vue.js component.angular.element($0).scope()
returns the Angular scope that is bound to the current DOM node.$0
When selecting a DOM element on a page, if you’re using Chrome, for example, you may have noticed the == $0
in the elements tree next to the currently highlighted element. That means that typing $0
in the console will give you access to the returned object’s properties and methods.
In Chrome you can see == $0
appended next to a selected DOM element and a title is displayed when you hover it.
Even though $0
is not displayed in the DOM elements tab, as in Chrome DevTools, typing $0
in the console works as expected in the other popular browsers too, as far as I tested.
Typing $0
in the Firefox browser’s console, reveals the current object’s methods and properties.
$0
on CSS pseudo-elements in the DOMEven though the CSS ::before
and ::after
pseudo-elements get displayed in browsers’ elements tree, they are not real DOM elements. Those elements are called pseudo because their content is generated by CSS, rather than HTML or JavaScript.
Pseudo-elements didn’t use to show up in the elements tree but now they do and I guess they’re not going to leave anywhere anytime soon. Having said that, if you abuse DOM element selection from browser’s Elements or Inspector tabs, there are some inconsistencies when it comes to what the console returns when typing $0
on the pseudo-elements selection:
A DevTools comparison between Chrome and Firefox on pseudo-elements when it comes to trying to get the current DOM node with $0
in the console.
You may notice the returned Restricted {}
object shown in the Firefox console when trying to get the current DOM node, which is a pseudo-element. At first sight, it’s not that quite self-explanatory.
Still, it seems that Firefox returns Object {}
, Inaccessible {}
or Restricted {}
objects apparently due to script security reasons while other browsers like Chrome for example even let you add a class on the current pseudo-elements nodes referred with $0
: $0.classList.add("what")
.
In Chrome DevTools, you can add a class on the currently selected CSS pseudo-element using the classList
property and the add()
method.
$r
When selecting a component in React DevTools and write $r
in the browser’s console, you get a reference to the selected component’s instance.
$vm0
Similar to the above, if having installed the Vue.js devtools to your browser, select the Vue component and then you’ll be able to interact with it in the browser’s console using $vm0
.
angular.element($0).scope()
Similar to React and Vue.js components, in Angular, a scope is an object that contains the application data and methods. Using the AngularJS Batarang extension in your browser, you can use angular.element($0).scope()
to get the Angular scope that is bound to the current DOM node $0
.
The newly released Edge browser supports extensions installed from other stores, e.g. Chrome Web Store, so that means that besides the well-known Chrome and Firefox support, now you get Microsoft Edge browser support too for the popular JavaScript frameworks.
Note that selecting the React and Vue.js components or Angular current scope mostly works for applications that are built in development mode. In most cases, when the production mode is set as true
, that is the intended behavior.
The DevTools naming convention is unanimously used by most of the popular browsers when it comes to their integrated development tools. Oh, and there’s Safari that uses Web Inspector.
Also, if debugging is something you’re interested in, you’ll also like the vanilla JS remove()
method and to fiddle with JS and the Clipboard API
.
While writing this article down, I also filled a bug report for this Chrome DevTools behavior. Two days later, the bug was fixed already and I couldn’t be impressed more!
]]>A classic scenario we all met in the wild is to copy an API token from an account settings form. I had to implement a similar example in the past weeks and decided to write this article down to show you an example of how to effectively do that.
There are two popular ways to copy to the clipboard:
execCommand()
method helps to manipulate editable form inputs or contentEditable
elements.navigator.clipboard
, is meant to supersede accessing the clipboard using the synchronous execCommand()
method.document.execCommand()
Using the execCommand()
method, you can perform operations or commands like copy, cut and paste when an HTML document has been switched to designMode
. If document.designMode === 'on'
, according to the specification, it means the entire document is editable.
To learn more about the syntax and full list of operations, MDN has a comprehensive entry about execCommand()
in its web docs.
navigator.clipboard
Further on, you’ll see how to copy to the clipboard using JS and the modern asynchronous Clipboard API, as the execCommand()
method is considered deprecated and superseded by this new Clipboard API.
The Clipboard API adds to the Navigator interface the read-only
clipboard
property, which returns the Clipboard object used to read and write the clipboard’s contents.
from MDN
API, interface, property, object… reading and assembling all these in mind might seem confusing but to keep it simple, the Clipboard API can help you to cut, copy and paste stuff on a web page.
click
The following HTML code might be merely a section on the account settings page. With using HTML mark
and code
elements, we’ll make sure we have some good default and native stylings offered by the browser.
For the sake of brevity, I queried the current token by the code
element but I assume that in production that will most probably be replaced by a unique identifier instead.
We’ll add a JS listener to the click
event type and before writing any other JavaScript lines, we’ll check out first if the Clipboard API is available in the browser:
In the end, considering the asynchronous behavior of the Clipboard API, check out the full code of the example. Also, here’s a CodePen demo too.
See the Pen API token by Catalin Rosu (@catalinred) on CodePen.
On security and permissions, the write permission is granted automatically but when it comes to the read permission, that must be requested specifically.
Read more on the interaction with the clipboard, including both write and read operations:
The browser support for the code above is strictly related to supporting Clipboard API in your browser because as Caniuse data shows, if the browser supports Clipboard API then most probably has support for JS async functions too.
If you’re targeting wider browser support for copying to clipboard, you may use clipboard.js, which is a 3KB gzipped library, based on both Selection and execCommand APIs and offers very good support for legacy browsers.
]]>textarea
resize handle using the CSS resize: none
declaration. Also, GitHub says there are more than 3 million code results in the wild for textarea
with CSS resize:none
applied.
I’m on Stack Overflow and feel kind of embarrassed about building reputation on recommending other people in the past to use CSS resize: none
on textarea
s. I’m not a power user but back in 2011, I did post an answer on Stack Overflow on removing the bottom-right corner dots in a textarea
. Also, the thing is that I still keep getting Stack Overflow reputation on that answer.
Never start an answer with just and never recommend other people to use CSS resize: none
in their stylesheets. You can do better than me!
resize:none
on textarea
is bad UXI think using the CSS resize:none
declaration on a textarea
is a bad decision when it comes to the user experience (UX) overall.
Very often, the textarea
is limited to a number of rows and columns or it has fixed width
and height
defined via CSS. Based solely on my own experience, while answering to forums, writing contact forms on websites, filling live chat popups or even private messaging on Twitter this is very frustrating.
Sometimes you need to type a long reply that consists of many paragraphs and wrapping that text within a tiny textarea box makes it hard to understand and to follow as you type. There were many times when I had to write that text within Notepad++ for example and then just paste the whole reply in that small textarea. I admit I also opened the DevTools to override the resize: none
declaration but that’s not really a productive way to do things.
According to MDN, the resize CSS property sets whether an element is resizable, and if so, in which directions. Also, it’s important to keep in mind that the resize
property does not apply to the inline elements and block elements for which the overflow property is set to visible
.
The CSS resize
property is often applied to textarea
in order to disable its resizability and this is what this article is about. I felt like an inner contradiction considering the amount of reputation I keep getting on my above Stack Overflow answer while finding on my own this bad UX. Besides that, it looks like the number of GitHub code results on this matter is growing, from 2 millions in 2017 as found by @humphd to more than 3 millions two years later.
textarea
sA common scenario is to have an auto-height textarea
element which basically expands as you type new rows. On this matter, Chris Ferdinandi wrote a good article on how to expand a textarea as the user types.
But besides the above, I’ve seen lots of JS hacks that involve using the CSS resize: none
declaration. There are alternatives to simulate the ‘textarea’ behavior and a popular one is using the classic div
with the boolean contentEditable
attribute value set to true
.
Here’s a more detailed and hopefully accessible example using ARIA roles on Twitter’s mobile version:
resize: none
everywhereBecause it’s a fancy new live chat widget and it’s a really high competition out there, everyone wants the most visually pleasing, catchy and cool box where to send a message from.
While most live chat apps use the classic HTML textarea
element, the implementations mostly rely on having listeners and adjust the CSS height
style based on the text contained within the box, with resize: none
declaration remaining, unfortunately, a constant presence in the CSS.
So, why resize: none
is so popular in this case?
To answer myself here, maybe if I’d have to write code for a popular live chat app, I wouldn’t want a textarea resize handle to ruin my beautiful component design freshly imported from Figma. Would I?
I guess I’d stick with resize: vertical
at the least, instead of ruining everything with resize: none
. Šime Vidas also tweeted that resize: vertical
is robust enough, and it’s cross browser.
You must really hate your users if textarea {resize: none}
is in your stylesheets. CSS resize none is bad for UX and you already know it:
Websites (@Uservoice) that add resize: none; to their textarea's. I don't want to deal with excessive word wrapping, getting 4 words per line on my 24 inch monitor. Why are you so worried about me doing that, that you add this CSS rule? @SuckyUX1
— Richard M Boos (@richboos) April 3, 2019
@AngelListCare can you remove resize: none and increase default height on textarea in /inbound messages when you are talking to candidates as a startup? It's TOO SMALL.
— Mev-Rael (@Mevrael) June 6, 2018
#css There's a website I use often that, for text boxes, has "resize: none" enabled for the TEXTAREA. Since the text box is really small, is there a way disable this on the domain entirely instead of doing it page by page? https://t.co/fh6ITQqdFp
— Dzmitry Radkevich (@gradar) May 16, 2018
next time I see a website with "resize: none" in their CSS for a textarea I expect a two page essay what the thought process behind it was
— Alexander Prinzhorn (@Prinzhorn) February 23, 2018
Dear @PeoplePerHour, if you're going to give me a really small textarea where I'm likely going to want to write a few paragraphs, at least remove the `resize:none` CSS so I can make it bigger myself. Cheers. 🤔 pic.twitter.com/iva97ezXQt
— Luke Harrison (@WebDevLuke) November 26, 2017
Putting `resize: none;` on a <textarea> is criminal behaviour. And yet "Showing 1,960,901 available code results" https://t.co/kCXhfz7MzM
— David Humphrey (@humphd) September 22, 2017
]]>you can explain to the web department that a textarea should never have a "resize:none;" property :)
— Louis Hoebregts (@Mamboleoo) June 10, 2016
title
tag, then Google grabs one for you from your h1
, later on you switch to a new domain and get stuck with the old website name. Oh and that’s because you didn’t add a website name this time either.
A Search Engine Results Page (SERP) is the list of results returned by a search engine as a response to a user’s query. For the sake of brevity, the term SERP is often used by the people in the SEO industry.
Also, the upper part of the first page of SERP is where your website pages have to be in order to receive higher traffic from a search engine.
So we know that Google changes the SERP result title depending on your search query, the reason is to show you, the searcher, the best content result based on your query.
Here’s Matt Cutts in a video in which he explains how Google chooses which titles to display in search results, it’s from 2014, but thought it’s relevant now too, given this article’s topic.
I updated my website back in November 2017, from red-team-design.com
to catalin.red
. Later on, while performing the usual double-check queries on Google, I noticed that the Google SERP was still showing obsolete title references containing the old domain website name:
A Google SERP example with one of my website’s article, containing the old website name.
Another SERP result with the “catalin.red” query, “Red Team Design” strikes again.
So I did what a normal person would do in this case. I went to Google Search Console -> URL inspection -> Crawled page tool preview for my above URL in question at that time and noticed there’s no website name in there, no “Red Team Design” or anything else.
In the meantime, I’ve also tested other search engines as Duckduckgo or Bing and randomly got kind of similar results which meant to me that they use a similar algorithm for storing / getting the website name from within the HTML page source.
I waited and waited but I’ve not seen any noticeable update in the SERP for my website pages and I proceeded further to adding the new website name back to my pages.
I’ve noticed the title
s were looking as they should in the SERP so apparently, overriding the website name in the title was the winner to say so.
Later on, in April I met John Muller, from Google Search Console, at SMX Munchen and I took advantage of the opportunity and asked him about this matter of mine. He was kind enough to answer to some of my questions and as far as I understood, Google stores a website name for your website and based on the fact that Google changes the SERP result title depending on your search query, I was seeing the old website name that Google kept stored.
I guess I was too ignorant about this SEO title matter, but learned lots of things along the way. For example, when Google grabs the website name for you, I can only assume it transforms the respective string from camelCase / PascalCase to Title case where appropriate. I stalked, I mean I met John again at Brighton, later in April 2019, and he confirmed that Google indeed tries that for your website name but it depends a lot of the website name in question.
In the end, having all my website’s code on Github, I was able to go back in time and build a sort of commits timeline related to this website name story of mine. Here’s a rough timeline attempt below, just in case:
This is the first GitHub commit with my website name stored in a YAML config file, back in 2014.
Having the above in the config file, according to the Jekyll documentation, you can later use it within your templates using site.name
.
So that’s what I did at that time, I added my ugly-but-unique RedTeamDesign
website name to an h1
. Later on, Google beautified and stored it as Red Team Design
by only using capital letters for the principal words. a.k.a Title case.
After the initial init, I added a custom logo using the CSS image replacement technique. But I guess at that time Google already had the website name stored from within the h1, as in the initial above commit.
In autumn 2017, I replaced the site.name
with Catalin Red and I also updated the logo from using the CSS image replacement technique to an inline SVG with an aria-label
attribute.
One year later, in 2018, I added the website name to the title
tag and that did the trick and that’s the end of story.
:focus-within
pseudo-class in order to tab through the dropdown menu items.
To avoid duplication, I thought it is a smart move to group this new fancy CSS :focus-within
pseudo-class with an existing selector. It was beautiful and it looked a lot like a progressive enhancement but in the end, it broke the entire CSS rule within browsers that do not support the CSS :focus-within
, e.g. IE.
Here’s the GitHub commit in question, the :focus-within
pseudo-class doesn’t work on IE, as the above CanIUse chart shows, thus the below CSS rule gets invalidated entirely according to W3C specs.
If just one of these selectors were invalid, the entire group of selectors would be invalid.
I learned the lesson, fixed the CSS selectors and wrote this down. Also, you might like the article I wrote on how to visually validate an input field using :placeholder-shown
and :focus-within
.
The meeting was cool, a success, not the first I was attending, but one question a student asked stuck in my mind and especially the answer that another speaker gave to that specific question.
Q- “What’s the difference between a front-end and a full-stack developer?”
A- “Well, think about a full-stack developer as a 3-in-1 person who can serve as a backend, a front-end and a DevOps”.
Well, hearing this 3-in-1 wording was weird, at least, especially when having this in mind, or this. But what do I know, I’m a front-end developer, sorry, web developer… I mean I sometimes do websites, when I’m not ranting.
I felt like I had to write this happening down but there are some good articles on this matter in the wild and I strongly advise to go read them:
Still, one thing was bothering me for some time, and namely how to efficiently include a minified, production-ready SVG icon system, using symbol
s within the Pug pages.
I had to find a better way to include an SVG icon system, both inline and minified, using symbol
s within the Pug generated files.
symbols.svg
output with imagemin
locals
object.The system that helps to generate the static files consists of gulp
, pug
, sass
, imagemin
, uglify
and all the front-end buzzwords you can think of. Lots of buzzwords, I told you I know how to make websites.
Leaving the joke aside, Pug, formerly Jade, has a simple mechanism to include non-Pug files as raw text and it works just fine.
All good except the fact that if you choose to minify the Pug files output, e.g. when in production
, if your included non-Pug files aren’t minified/uglified already, you’ll end up with some mixed output in your final HTML source file.
Mixed HTML code output, both minified and non-minified
In the beginning, I have to admit I started by having two files to maintain: symbols.svg
and symbols.min.svg
and whenever a new symbol was added to symbols.svg
, had to update the symbols.min.svg
file too. I’m not so proud of this, but it worked, and I knew I had to find a better way to handle this situation.
New year, new ideas.
It’s not new year’s resolution or something like that, but the first thing I made when got back to work in 2019, besides updating the footers to © 2019 :), was to handle this SVG inline include in my Pug files.
Here’s how the symbols.svg
icon system looks like:
The display
attribute lets you control the rendering of graphical or container elements. No need to add any CSS class helper to visually hide the SVG content. More on MDN.
The following gulp task excerpt will move and optimize the symbols.svg
. Note the SVGO options that we’re passing on for our SVG, they are useful and mandatory in this case otherwise lots of stuff will get removed from the optimized output.
Within the pugTask
, I’m passing the already minified SVG file as a property of the locals
object, which is part of the Pug API. Also, I always make sure the above gulp imagesTask
runs before the pugTask
, in order to have the locals.svg
available. As I just switched everything to gulp 4, I use series() to execute tasks one after another.
Finally, I’ll be able to include the minified result in a partial Pug file using a dot block of plain text and unescaped string interpolation:
Better, beautiful & minified HTML output
I’m pretty happy I managed to find a way to improve this piece within my build process and will dig even further to see how to improve things. Let me know if you know a better way to do it, would love to hear it!
]]>