:not – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Tue, 20 Dec 2022 17:42:26 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.1 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 :not – CSS-Tricks https://css-tricks.com 32 32 45537868 A Pure CSS Gallery Focus Effect with :not https://css-tricks.com/a-pure-css-gallery-focus-effect-with-not/ https://css-tricks.com/a-pure-css-gallery-focus-effect-with-not/#comments Thu, 13 Oct 2022 15:10:15 +0000 https://css-tricks.com/?p=373508 Oftentimes in the past, I needed to figure out how to add styles to all elements inside the container but not the hovered one.

Demo of the expected “fade-out” effect on siblings to let users “focus” on a particular element.…


A Pure CSS Gallery Focus Effect with :not originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Oftentimes in the past, I needed to figure out how to add styles to all elements inside the container but not the hovered one.

Animated GIF of a mouse cursor hovering over elements. The element the mouse cursor enters remains visible and the other elements fade.
Demo of the expected “fade-out” effect on siblings to let users “focus” on a particular element.

This effect requires selecting the siblings of a hovered element. I used to apply JavaScript for this, adding or removing the class that defined the proper CSS rules on mouseenter and mouseleave events, similar to this:

Although the code does the trick, my gut feeling always told me that there must be some pure-CSS way to achieve the same result. A few years ago, while working on a certain slider for my company, I came up with a solution similar to how Chris Geelhoed recreated the famous Netflix homepage animation and I understood that I didn’t need JavaScript for this anymore.

A couple of months ago I was trying to implement the same approach to a grid-based feed on my company website and — boom — it didn’t work because of the gap between the elements!

Luckily for me, it appeared that it doesn’t have to stay like this, and once again I didn’t need JavaScript for it.

Markup and base CSS

Let’s start coding by preparing the proper markup:

  • .grid is a grid-based <ul> list;
  • and .grid__child elements are <li> children that we want to interact with.

The markup looks like this:

<ul class="grid">
  <li class="grid__child"></li>
  <li class="grid__child"></li>
  <li class="grid__child"></li>
</ul>

The style should look like this:

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, 15rem);
  grid-gap: 1rem;
}

.grid__child {
  background: rgba(0, 0, 0, .1);
  border-radius: .5rem;
  aspect-ratio: 1/1;
}

This example code will create three list items occupying three columns in a grid.

The power of CSS selectors

Now, let’s add some interactivity. The approach that I initially applied was based on two steps:

  1. hovering on the container should change the styles of all elements inside…  
  2. …except the one that cursor is hovering at the moment.

Let’s start with grabbing every child while the cursor is hovering over the container:

.grid:hover .grid__child {
  /* ... */
}

Secondly, let’s exclude the currently hovered item and reduce the opacity of any other child:

.grid:hover .grid__child:not(:hover) {
  opacity: 0.3;
}

And this would be perfectly enough for containers without gaps between the child elements:

Animated GIF of a mouse cursor interacting with elements that are not separated by any gaps.
Demo of a solution that works without gaps.

However, in my case, I couldn’t remove these gaps:

Animated GIF of a mouse cursor hovering over elements. However, when the mouse enters a gap between two elements, the effect ends as the mouse leaves the element.
Demo of the problem encountered when gaps are introduced.

When I was moving the mouse between the tiles all of the children elements were fading out.

Ignoring the gaps

We can assume that gaps are parts of the container that are not overlayed by its children. We don’t want to run the effect every time the cursor enters the container, but rather when it hovers over one of the elements inside. Can we ignore the cursor moving above the gaps then? 

Yes, we can, using pointer-events: none on the .grid container and bringing them back with pointer-events: auto on its children:

.grid {
  /* ... */
  pointer-events: none;
}

/* ... */

.grid__child {
  /* ... */
  pointer-events: auto;
}

Let’s just add some cool transition on opacity and we have a ready component:

It’s probably even cooler when we add more tiles and create a 2-dimensional layout:

The final CSS looks like this:

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, 15rem);
  grid-gap: 3rem;
  pointer-events: none;
}

.grid:hover .grid__child:not(:hover) {
  opacity: 0.3;
}

.grid__child {
  background: rgba(0, 0, 0, .1);
  border-radius: .5rem;
  aspect-ratio: 1/1;
  pointer-events: auto;
  transition: opacity 300ms;
}

With only 2 additional lines of code we overcame the gap problem!

Possible issues

Although it’s a compact solution, there are some situations where it might require some workarounds.

Unfortunately, this trick won’t work when you want the container to be scrollable, e.g., like in some kind of horizontal slider. The pointer-events: none style would ignore not only the hover event but all the others, too. In such situations, you can wrap the .grid in another container, like this:

<div class="container">
  <ul class="grid">
    <li class="grid__child"></li>
    <li class="grid__child"></li>
    <li class="grid__child"></li>
    <li class="grid__child"></li>
    <li class="grid__child"></li>
    <li class="grid__child"></li>
    <li class="grid__child"></li>
  </ul>
</div>

Summary

I strongly encourage you to experiment and try to find a simpler and more native approach for tasks that are usually expected to have some level of complexity. Web technologies, like CSS, are getting more and more powerful and by using out-of-the-box native solutions you can achieve great results without the need of maintaining your code and cede it to browser vendors.

I hope that you liked this short tutorial and found it useful. Thanks!

The author selected the Tech Education Fund to receive a donation as part of the Write for DOnations program.


A Pure CSS Gallery Focus Effect with :not originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/a-pure-css-gallery-focus-effect-with-not/feed/ 3 373508
Detecting Specific Text Input with HTML and CSS https://css-tricks.com/detecting-specific-text-input-with-html-and-css/ https://css-tricks.com/detecting-specific-text-input-with-html-and-css/#comments Tue, 09 Nov 2021 22:53:45 +0000 https://css-tricks.com/?p=356142 Louis Lazaris breaks down some bonafide CSS trickery from Jane. The Pen shows off interactivity where:

  1. You have to press a special combination of keys on a keyboard.
  2. Then type a secret password.

From there, a special message pops …


Detecting Specific Text Input with HTML and CSS originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Louis Lazaris breaks down some bonafide CSS trickery from Jane. The Pen shows off interactivity where:

  1. You have to press a special combination of keys on a keyboard.
  2. Then type a secret password.

From there, a special message pops up on the screen. Easily JavaScript territory, but no, this is done here entirely in HTML and CSS, which is wild.

A lot of little known features and tricks is combined here to pull this off, like HTML’s accesskey and pattern attributes, as well as :not(), :placeholder-shown, and :valid in CSS—not to mention the custom property toggle trick.

That’s… wow. And yet, look how very little code it is.

To Shared LinkPermalink on CSS-Tricks


Detecting Specific Text Input with HTML and CSS originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/detecting-specific-text-input-with-html-and-css/feed/ 1 356142
The CSS :has Selector (and 4+ Examples) https://css-tricks.com/the-css-has-selector/ https://css-tricks.com/the-css-has-selector/#comments Wed, 17 Mar 2021 18:40:16 +0000 https://css-tricks.com/?p=336424 The CSS :has selector helps you select elements when they contain other elements that match the selector you pass into :has().


The CSS :has Selector (and 4+ Examples) originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The CSS :has selector helps you select elements that contain elements that match the selector you pass into the :has() function. It’s essentially a “parent” selector, although far more useful than just that. For example, imagine being able to select all <div>s but only when they contain a <p>. That’s what we can do:

div:has(p) {
  background: red;
}
/*
  <div> <!-- selected! -->
     <p></p>
  <div>

  <div></div> <!-- not selected -->
  <div> <!-- not selected -->
    <section></section>
  </div>
*/

Although it’s not supported in any browser as I write, it has now dropped in Safari Technical Preview 137, so it’s starting to happen!

Pretty darn handy right! Here’s another example. Say you want space after your headers. Of course! A bit of margin-block-end on your h2 should do it. But… what if there is a subtitle? Now we can select a parent on the condition a subtitle is present and adjust the spacing.

h2,
.subtitle {
  margin: 0 0 1.5rem 0;
}
.header-group:has(h2):has(.subtitle) h2 {
  margin: 0 0 0.2rem 0; /* reduce spacing on header, because subtitle will handle it */
}

/*
  <div class="header-group">
    <h2>Blog Post Title</h2> <!-- main spacing applied here -->
  </div>

  <div class="header-group">
    <h2>Blog Post Title</h2>
    <div class="subtitle"> <!-- main spacing applied here -->
      This is a subtitle
    </div>
  </div>
*/
The CSS :has selector being helpful in spacing headers with subtitles (or not).
On the left, the main spacing happens after the h2, on the right, the main spacing happens after the subtitle.

The way I think about :has is this: it’s a parent selector pseudo-class. That is CSS-speak for “it lets you change the parent element if it has a child or another element that follows it.” This might feel weird! It might break your mental model of how CSS works. This is how I’m used to thinking about CSS:

.parent .child {
  color: red;
}

You can only style down, from parent to child, but never back up the tree. :has completely changes this because up until now there have been no parent selectors in CSS and there are some good reasons why. Because of the way in which browsers parse HTML and CSS, selecting the parent if certain conditions are met could lead to all sorts of performance concerns.

If I sit down and think about all the ways I might use :has today, I sort of get a headache. It would open up this pandora’s box of opportunities that have never been possible with CSS alone.

Another example: let’s say we want to only apply styles to links that have images in them:

a:has(> img) {
  border: 20px solid white;
}

This would be helpful from time to time. I can also see :has being used for conditionally adding margin and padding to elements depending on their content. That would be neat.

The :has selector is part of the CSS Selectors Level 4 specification which is the same spec that has the extremely useful :not pseudo-class.


You could argue that the CSS :has selector is more powerful than just a “parent” selector, which is exactly what Bramus has done! Like in the subheadings example above, you aren’t necessarily ultimately selecting the parent, you might select the parent in a has-condition, but then ultimately select a child element from there.

/*  Matches <figure> elements that have a <figcaption> as a child element */
figure:has(figcaption) { … }

/* Matches <img> elements that is a child of a <figure> that contains a <figcaption> child element */
figure:has(figcaption) img { … }

There you can quickly see that the second selector is selecting a child <img>, not just the parent of the <figcaption>.

Selector List

You can chain it:

article:has(h2):has(ul) {

}

Or give it a selector list:

article:has(h2, ul) {

}

And the list is forgiving: The list is no longer “forgiving” after the W3C adopted a resolution in December 2020 in response to a reported issue. So, if the selector list contains even one invalid argument, the entire list is ignored:

/* 👎 */
article:has(h2, ul, ::-blahdeath) {
  /* ::blahdeath is invalid, making the entire selector invalid. */
}

A workaround is to nest a more forgiving selector in there, such as :is() or :where():

/* 👍 */
article:has(:where(h2, ul, ::-blahdeath)) {
  /* :where is a forgiving selector, making this valid. */
}

Testing for Support

@supports(selector(:has(p))) {
  /* Supported! */
}

The :not() selector is part of the same spec…

Unlike :has, :not does have pretty decent browser support and I used it for the first time the other day:

ul li:not(:first-of-type) {
  color: red;
}

That’s great I also love how gosh darn readable it is; you don’t ever have to have seen this line of code to understand what it does.

Another way you can use :not is for margins:

ul li:not(:last-of-type) {
  margin-bottom: 20px;
}

So every element that is not the last item gets a margin. This is useful if you have a bunch of elements in a card, like this:

… and also :is() and :where()

CSS Selectors Level 4 is also the same spec that has the :is selector that can be used like this today in a lot of browsers:

:is(section, article, aside, nav) :is(h1, h2, h3, h4, h5, h6) {
  color: #BADA55;
}

/* ... which would be the equivalent of: */
section h1, section h2, section h3, section h4, section h5, section h6, 
article h1, article h2, article h3, article h4, article h5, article h6, 
aside h1, aside h2, aside h3, aside h4, aside h5, aside h6, 
nav h1, nav h2, nav h3, nav h4, nav h5, nav h6 {
  color: #BADA55;
}

More Info

So that’s it! :has should be quite useful to use soon, and its cousins :is and :not can be fabulously helpful already and that’s only a tiny glimpse — just three CSS pseudo-classes — that are available in this new spec.


The CSS :has Selector (and 4+ Examples) originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/the-css-has-selector/feed/ 29 336424
Form Validation Styling on Input Focus https://css-tricks.com/snippets/css/form-validation-styling-on-input-focus/ https://css-tricks.com/snippets/css/form-validation-styling-on-input-focus/#comments Mon, 08 Mar 2021 16:03:44 +0000 https://css-tricks.com/?page_id=335874 /* Only show invalid ring while not focused */ input:not(:focus):not(:placeholder-shown):invalid { border-color: var(--color-invalid); } input:not(:focus):not(:placeholder-shown):invalid ~ .error-message { display: block; } /* Only show valid ring while not focused and if a value is entered */ /* :empty won't work


Form Validation Styling on Input Focus originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
/* Only show invalid ring while not focused */ input:not(:focus):not(:placeholder-shown):invalid { border-color: var(--color-invalid); } input:not(:focus):not(:placeholder-shown):invalid ~ .error-message { display: block; } /* Only show valid ring while not focused and if a value is entered */ /* :empty won't work here as that targets elements that have no childeren. Therefore we abuse :placeholder-shown */ input:not(:focus):not(:placeholder-shown):valid { border-color: var(--color-valid); }

Pulling this straight from the Weekly Platform News, where Šime Vidas covers two long ongoing issues with using :invalid to style form input validation. Apparently, what happens is…

  • [inputs] become :invalid while the user is still typing the value.
  • If a form field is required (), it will become :invalid immediately on page load.

Both of these behaviors are potentially confusing (and annoying), so websites cannot rely solely on the :invalid selector to indicate that a value entered by the user is not valid. However, there is the option to combine :invalid with :not(:focus) and even :not(:placeholder-shown) to ensure that the page’s “invalid” styles do not apply to the <input> until the user has finished entering the value and moved focus to another element.

Ryan Florence sums this up nicely in a tweet:

So, what this snippet does is enhance :invalid by combining it with :not(:focus) and :not(:placeholder-shown).

What does that mean? Let’s translate the code into something more readable.

input:not(:focus):not(:placeholder-shown):invalid {}

If an input is not in focus, its placeholder text isn’t shown, and the entered text is invalid… then you can use these styles.

In other words, this prevents the invalid style from being applied until text is entered and focus moves to another element.

input:not(:focus):not(:placeholder-shown):invalid ~ .error-message

Hey, let’s display the error message if those same conditions are met.

This is the exact same thing as above, but selects an .error-message class and sets it from display: none to display: block only after the text is entered and focus moves from the input to something else.

input:not(:focus):not(:placeholder-shown):valid

Oh, the text that’s entered is valid? OK, let’s apply these styles instead.

Again, the same sorta condition, but chained to :valid instead of :invalid. That way, we can give the user a different set of styles to indicate that what they typed is good to go!

According to Šime, this sort of snippet might be unnecessary in the future as a greater push is being made for :user-invalid and :user-valid. Firefox already intends to ship its un-prefixed solution. Tickets are open to do the same in Safari and Chrome.


Form Validation Styling on Input Focus originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/snippets/css/form-validation-styling-on-input-focus/feed/ 4 335874
Weekly Platform News: Focus Rings, Donut Scope, More em Units, and Global Privacy Control https://css-tricks.com/weekly-platform-news-focus-rings-donut-scope-ditching-em-units-and-global-privacy-control/ https://css-tricks.com/weekly-platform-news-focus-rings-donut-scope-ditching-em-units-and-global-privacy-control/#comments Thu, 04 Mar 2021 21:33:01 +0000 https://css-tricks.com/?p=335856 In this week’s news, Chrome tackles focus rings, we learn how to get “donut” scope, Global Privacy Control gets big-name adoption, it’s time to ditch pixels in media queries, and a snippet that prevents annoying form validation styling.

Chrome will…


Weekly Platform News: Focus Rings, Donut Scope, More em Units, and Global Privacy Control originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In this week’s news, Chrome tackles focus rings, we learn how to get “donut” scope, Global Privacy Control gets big-name adoption, it’s time to ditch pixels in media queries, and a snippet that prevents annoying form validation styling.

Chrome will stop displaying focus rings when clicking buttons

Chrome, Edge, and other Chromium-based browsers display a focus indicator (a.k.a. focus ring) when the user clicks or taps a (styled) button. For comparison, Safari and Firefox don’t display a focus indicator when a button is clicked or tapped, but do only when the button is focused via the keyboard.

The focus ring will stay on the button until the user clicks somewhere else on the page.

Some developers find this behavior annoying and are using various workarounds to prevent the focus ring from appearing when a button is clicked or tapped. For example, the popular what-input library continuously tracks the user’s input method (mouse, keyboard or touch), allowing the page to suppress focus rings specifically for mouse clicks.

[data-whatintent="mouse"] :focus {
  outline: none;
}

A more recent workaround was enabled by the addition of the CSS :focus-visible pseudo-class to Chromium a few months ago. In the current version of Chrome, clicking or tapping a button invokes the button’s :focus state but not its :focus-visible state. that way, the page can use a suitable selector to suppress focus rings for clicks and taps without affecting keyboard users.

:focus:not(:focus-visible) {
  outline: none;
}

Fortunately, these workarounds will soon become unnecessary. Chromium’s user agent stylesheet recently switched from :focus to :focus-visible, and as a result of this change, button clicks and taps no longer invoke focus rings. The new behavior will first ship in Chrome 90 next month.

The enhanced CSS :not() selector enables “donut scope”

I recently wrote about the A:not(B *) selector pattern that allows authors to select all A elements that are not descendants of a B element. This pattern can be expanded to A B:not(C *) to create a “donut scope.”

For example, the selector article p:not(blockquote *) matches all <p> elements that are descendants of an <article> element but not descendants of a <blockquote> element. In other words, it selects all paragraphs in an article except the ones that are in a block quotation.

The donut shape that gives this scope its name

The New York Times now honors Global Privacy Control

Announced last October, Global Privacy Control (GPC) is a new privacy signal for the web that is designed to be legally enforceable. Essentially, it’s an HTTP Sec-GPC: 1 request header that tells websites that the user does not want their personal data to be shared or sold.

The DuckDuckGo Privacy Essentials extension enables GPC by default in the browser

The New York Times has become the first major publisher to honor GPC. A number of other publishers, including The Washington Post and Automattic (WordPress.com), have committed to honoring it “this coming quarter.”

From NYT’s privacy page:

Does The Times support the Global Privacy Control (GPC)?

Yes. When we detect a GPC signal from a reader’s browser where GDPR, CCPA or a similar privacy law applies, we stop sharing the reader’s personal data online with other companies (except with our service providers).

The case for em-based media queries

Some browsers allow the user to increase the default font size in the browser’s settings. Unfortunately, this user preference has no effect on websites that set their font sizes in pixels (e.g., font-size: 20px). In part for this reason, some websites (including CSS-Tricks) instead use font-relative units, such as em and rem, which do respond to the user’s font size preference.

Ideally, a website that uses font-relative units for font-size should also use em values in media queries (e.g., min-width: 80em instead of min-width: 1280px). Otherwise, the site’s responsive layout may not always work as expected.

For example, CSS-Tricks switches from a two-column to a one-column layout on narrow viewports to prevent the article’s lines from becoming too short. However, if the user increases the default font size in the browser to 24px, the text on the page will become larger (as it should) but the page layout will not change, resulting in extremely short lines at certain viewport widths.

If you’d like to try out em-based media queries on your website, there is a PostCSS plugin that automatically converts min-width, max-width, min-height, and max-height media queries from px to em.

(via Nick Gard)

A new push to bring CSS :user-invalid to browsers

In 2017, Peter-Paul Koch published a series of three articles about native form validation on the web. Part 1 points out the problems with the widely supported CSS :invalid pseudo-class:

  • The validity of <input> elements is re-evaluated on every key stroke, so a form field can become :invalid while the user is still typing the value.
  • If a form field is required (<input required>), it will become :invalid immediately on page load.

Both of these behaviors are potentially confusing (and annoying), so websites cannot rely solely on the :invalid selector to indicate that a value entered by the user is not valid. However, there is the option to combine :invalid with :not(:focus) and even :not(:placeholder-shown) to ensure that the page’s “invalid” styles do not apply to the <input> until the user has finished entering the value and moved focus to another element.

The CSS Selectors module defines a :user-invalid pseudo-class that avoids the problems of :invalid by only matching an <input> “after the user has significantly interacted with it.”

Firefox already supports this functionality via the :-moz-ui-invalid pseudo-class (see it in action). Mozilla now intends to un-prefix this pseudo-class and ship it under the standard :user-invalid name. There are still no signals from other browser vendors, but the Chromium and WebKit bugs for this feature have been filed.


Weekly Platform News: Focus Rings, Donut Scope, More em Units, and Global Privacy Control originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/weekly-platform-news-focus-rings-donut-scope-ditching-em-units-and-global-privacy-control/feed/ 3 335856
Weekly Platform News: The :not() pseudo-class, Video Media Queries, clip-path: path() Support https://css-tricks.com/weekly-platform-news-the-not-pseudo-class-video-media-queries-clip-path-path-support/ https://css-tricks.com/weekly-platform-news-the-not-pseudo-class-video-media-queries-clip-path-path-support/#comments Fri, 05 Feb 2021 21:02:30 +0000 https://css-tricks.com/?p=333984 Hey, we’re back with weekly updates about the browser landscape from Šime Vidas.

In this week’s update, the CSS :not pseudo class can accept complex selectors, how to disable smooth scrolling when using “Find on page…” in Chrome, Safari’s …


Weekly Platform News: The :not() pseudo-class, Video Media Queries, clip-path: path() Support originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Hey, we’re back with weekly updates about the browser landscape from Šime Vidas.

In this week’s update, the CSS :not pseudo class can accept complex selectors, how to disable smooth scrolling when using “Find on page…” in Chrome, Safari’s support for there media attribute on <video> elements, and the long-awaited debut of the path() function for the CSS clip-path property.

Let’s jump into the news…

The enhanced :not() pseudo-class enables new kinds of powerful selectors

After a years-long wait, the enhanced :not() pseudo-class has finally shipped in Chrome and Firefox, and is now supported in all major browser engines. This new version of :not() accepts complex selectors and even entire selector lists.

For example, you can now select all <p> elements that are not contained within an <article> element.

/* select all <p>s that are descendants of <article> */
article p {
}

/* NEW! */
/* select all <p>s that are not descendants of <article> */
p:not(article *) {
}

In another example, you may want to select the first list item that does not have the hidden attribute (or any other attribute, for that matter). The best selector for this task would be :nth-child(1 of :not([hidden])), but the of notation is still only supported in Safari. Luckily, this unsupported selector can now be re-written using only the enhanced :not() pseudo-class.

/* select all non-hidden elements that are not preceded by a non-hidden sibling (i.e., select the first non-hidden child */
:not([hidden]):not(:not([hidden]) ~ :not([hidden])) {
}

The HTTP Refresh header can be an accessibility issue

The HTTP Refresh header (and equivalent HTML <meta> tag) is a very old and widely supported non-standard feature that instructs the browser to automatically and periodically reload the page after a given amount of time.

<!-- refresh page after 60 seconds -->
<meta http-equiv="refresh" content="60">

According to Google’s data, the <meta http-equiv="refresh"> tag is used by a whopping 2.8% of page loads in Chrome (down from 4% a year ago). All these websites risk failing several success criteria of the Web Content Accessibility Guidelines (WCAG):

If the time interval is too short, and there is no way to turn auto-refresh off, people who are blind will not have enough time to make their screen readers read the page before the page refreshes unexpectedly and causes the screen reader to begin reading at the top.

However, WCAG does allow using the <meta http-equiv="refresh"> tag specifically with the value 0 to perform a client-side redirect in the case that the author does not control the server and hence cannot perform a proper HTTP redirect.

(via Stefan Judis)

How to disable smooth scrolling for the “Find on page…” feature in Chrome

CSS scroll-behavior: smooth is supported in Chrome and Firefox. When this declaration is set on the <html> element, the browser scrolls the page “in a smooth fashion.” This applies to navigations, the standard scrolling APIs (e.g., window.scrollTo({ top: 0 })), and scroll snapping operations (CSS Scroll Snap).

Unfortunately, Chrome erroneously keeps smooth scrolling enabled even when the user performs a text search on the page (“Find on page…” feature). Some people find this annoying. Until that is fixed, you can use Christian Schaefer’s clever CSS workaround that effectively disables smooth scrolling for the “Find on page…” feature only.

@keyframes smoothscroll1 {
  from,
  to {
    scroll-behavior: smooth;
  }
}

@keyframes smoothscroll2 {
  from,
  to {
    scroll-behavior: smooth;
  }
}

html {
  animation: smoothscroll1 1s;
}

html:focus-within {
  animation-name: smoothscroll2;
  scroll-behavior: smooth;
}

In the following demo, notice how clicking the links scrolls the page smoothly while searching for the words “top” and “bottom” scrolls the page instantly.

Safari still supports the media attribute on video sources

With the HTML <video> element, it is possible to declare multiple video sources of different MIME types and encodings. This allows websites to use more modern and efficient video formats in supporting browsers, while providing a fallback for other browsers.

<video>
  <source src="/flower.webm" type="video/webm">
  <source src="/flower.mp4" type="video/mp4">
</video>

In the past, browsers also supported the media attribute on video sources. For example, a web page could load a higher-resolution video if the user’s viewport exceeded a certain size.

<video>
  <source media="(min-width: 1200px)" src="/large.mp4" type="video/mp4">
  <source src="/small.mp4" type="video/mp4">
</video>

The above syntax is in fact still supported in Safari today, but it was removed from other browsers around 2014 because it was not considered a good feature:

It is not appropriate for choosing between low resolution and high resolution because the environment can change (e.g., the user might fullscreen the video after it has begun loading and want high resolution). Also, bandwidth is not available in media queries, but even if it was, the user agent is in a better position to determine what is appropriate than the author.

Scott Jehl (Filament Group) argues that the removal of this feature was a mistake and that websites should be able to deliver responsive video sources using <video> alone.

For every video we embed in HTML, we’re stuck with the choice of serving source files that are potentially too large or small for many users’ devices … or resorting to more complicated server-side or scripted or third-party solutions to deliver a correct size.

Scott has written a proposal for the reintroduction of media in video <source> elements and is welcoming feedback.

The CSS clip-path: path() function ships in Chrome

It wasn’t mentioned in the latest “New in Chrome 88” article, but Chrome just shipped the path() function for the CSS clip-path property, which means that this feature is now supported in all three major browser engines (Safari, Firefox, and Chrome).

The path() function is defined in the CSS Shapes module, and it accepts an SVG path string. Chris calls this the ultimate syntax for the clip-path property because it can clip an element with “literally any shape.” For example, here’s a photo clipped with a heart shape:


Weekly Platform News: The :not() pseudo-class, Video Media Queries, clip-path: path() Support originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/weekly-platform-news-the-not-pseudo-class-video-media-queries-clip-path-path-support/feed/ 6 333984
CSS :not() with Multiple Classes https://css-tricks.com/css-not-with-multiple-classes/ https://css-tricks.com/css-not-with-multiple-classes/#comments Mon, 22 Jul 2019 21:39:06 +0000 https://css-tricks.com/?p=292867 Say you want to select an element when it doesn’t have a certain class. That’s what the :not() selector is for.

body:not(.home) {
  
}

But what if there are multiple classes you want to avoid?

There are no logical combinators …


CSS :not() with Multiple Classes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Say you want to select an element when it doesn’t have a certain class. That’s what the :not() selector is for.

body:not(.home) {
  
}

But what if there are multiple classes you want to avoid?

There are no logical combinators with :not(), like and or or, but you can chain them, which is effectively like and.

body:not(.home):not(.away):not(.page-50) {
  
}

The :not() selector doesn’t add any specificy by itself, but what is inside does, so :not(.foo) adds the same weight as .foo does.


CSS :not() with Multiple Classes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/css-not-with-multiple-classes/feed/ 21 292867
Using Feature Detection, Conditionals, and Groups with Selectors https://css-tricks.com/using-feature-detection-conditionals-and-groups-with-selectors/ https://css-tricks.com/using-feature-detection-conditionals-and-groups-with-selectors/#comments Fri, 19 Oct 2018 14:18:58 +0000 http://css-tricks.com/?p=277540 CSS is designed in a way that allows for relatively seamless addition of new features. Since the dawn of the language, specifications have required browsers to gracefully ignore any properties, values, selectors, or at-rules they do not support. Consequently, in …


Using Feature Detection, Conditionals, and Groups with Selectors originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
CSS is designed in a way that allows for relatively seamless addition of new features. Since the dawn of the language, specifications have required browsers to gracefully ignore any properties, values, selectors, or at-rules they do not support. Consequently, in most cases, it is possible to successfully use a newer technology without causing any issues in older browsers.

Consider the relatively new caret-color property (it changes the color of the cursor in inputs). Its support is still low but that does not mean that we should not use it today.

.myInput {
  color: blue;
  caret-color: red;
}

Notice how we put it right next to color, a property with practically universal browser support; one that will be applied everywhere. In this case, we have not explicitly discriminated between modern and older browsers. Instead, we just rely on the older ones ignoring features they do not support.

It turns out that this pattern is powerful enough in the vast majority of situations.

When feature detection is necessary

In some cases, however, we would really like to use a modern property or property value whose use differs significantly from its fallback. In those cases, @supports comes to the rescue.

@supports is a special at-rule that allows us to conditionally apply any styles in browsers that support a particular property and its value.

@supports (display: grid) {
  /* Styles for browsers that support grid layout... */
}

It works analogously to @media queries, which also only apply styles conditionally when a certain predicate is met.

To illustrate the use of @supports, consider the following example: we would like to display a user-uploaded avatar in a nice circle but we cannot guarantee that the actual file will be of square dimensions. For that, the object-fit property would be immensely helpful; however, it is not supported by Internet Explorer (IE). What do we do then?

Let us start with markup:

<div class="avatar">
  <img class="avatar-image" src="..." alt="..." />
</div>

As a not-so-pretty fallback, we will squeeze the image width within the avatar at the cost that wider files will not completely cover the avatar area. Instead, our single-color background will appear underneath.

.avatar {
  position: relative;
  width: 5em;
  height: 5em;
  border-radius: 50%;
  overflow: hidden;
  background: #cccccc; /* Fallback color */
}

.avatar-image {
  position: absolute;
  top: 50%;
  right: 0;
  bottom: 0;
  left: 50%;
  transform: translate(-50%, -50%);
  max-width: 100%;
}

You can see this behavior in action here:

See the Pen Demo fallback for object-fit by Jirka Vebr (@JirkaVebr) on CodePen.

Notice there is one square image, a wide one, and a tall one.

Now, if we use object-fit, we can let the browser decide the best way to position the image, namely whether to stretch the width, height, or neither.

@supports (object-fit: cover) {
  .avatar-image {
    /* We no longer need absolute positioning or any transforms */
    position: static;
    transform: none;
    object-fit: cover;
    width: 100%;
    height: 100%;
  }
}

The result, for the same set of image dimensions, works nicely in modern browsers:

See the Pen @supports object-fit demo by Jirka Vebr (@JirkaVebr) on CodePen.

Conditional selector support

Even though the Selectors Level 4 specification is still a Working Draft, some of the selectors it defines — such as :placeholder-shown — are already supported by many browsers. Should this trend continue (and should the draft retain most of its current proposals), this level of the specification will introduce more new selectors than any of its predecessors. In the meantime, and also while IE is still alive, CSS developers will have to target a yet more diverse and volatile spectrum of browsers with nascent support for these selectors.

It will be very useful to perform feature detection on selectors. Unfortunately, @supports is only designed for testing support of properties and their values, and even the newest draft of its specification does not appear to change that. Ever since its inception, it has, however, defined a special production rule in its grammar whose sole purpose is to provide room for potential backwards-compatible extensions, and thus it is perfectly feasible for a future version to add the ability to condition on support for particular selectors. Nevertheless, that eventuality remains entirely hypothetical.

Selector counterpart to @supports

First of all, it is important to emphasize that, analogous to the aforementioned caret-color example where @supports is probably not necessary, many selectors do not need to be explicitly tested for either. For instance, we might simply try to match ::selection and not worry about browsers that do not support it since it will not be the end of the world if the selection appearance remains the browser default.

Nevertheless, there are cases where explicit feature detection for selectors would be highly desirable. In the rest of this article, we will introduce a pattern for addressing such needs and subsequently use it with :placeholder-shown to build a CSS-only alternative to the Material Design text field with a floating label.

Fundamental property groups of selectors

In order to avoid duplication, it is possible to condense several identical declarations into one comma-separated list of selectors, which is referred to as group of selectors.

Thus we can turn:

.foo { color: red }
.bar { color: red }

…into:

.foo, .bar { color: red }

However, as the Selectors Level 3 specification warns, these are only equivalent because all of the selectors involved are valid. As per the specification, if any of the selectors in the group is invalid, the entire group is ignored. Consequently, the selectors:

..foo { color: red } /* Note the extra dot */
.bar { color: red }

…could not be safely grouped, as the former selector is invalid. If we grouped them, we would cause the browser to ignore the declaration for the latter as well.

It is worth pointing out that, as far as a browser is concerned, there is no difference between an invalid selector and a selector that is only valid as per a newer version of the specification, or one that the browser does not know. To the browser, both are simply invalid.

We can take advantage of this property to test for support of a particular selector. All we need is a selector that we can guarantee matches nothing. In our examples, we will use :not(*).

.foo { color: red }

:not(*):placeholder-shown,
.foo {
  color: green
}

Let us break down what is happening here. An older browser will successfully apply the first rule, but when processing the the rest, it will find the first selector in the group invalid since it does not know :placeholder-shown, and thus it will ignore the entire selector group. Consequently, all elements matching .foo will remain red. In contrast, while a newer browser will likely roll its robot eyes upon encountering :not(*) (which never matches anything) it will not discard the entire selector group. Instead, it will override the previous rule, and thus all elements matching .foo will be green.

Notice the similarity to @supports (or any @media query, for that matter) in terms of how it is used. We first specify the fallback and then override it for browsers that satisfy a predicate, which in this case is the support for a particular selector — albeit written in a somewhat convoluted fashion.

See the Pen @supports for selectors by Jirka Vebr (@JirkaVebr) on CodePen.

Real-world example

We can use this technique for our input with a floating label to separate browsers that do from those that do not support :placeholder-shown, a pseudo-class that is absolutely vital to this example. For the sake of relative simplicity, in spite of best UI practices, we will choose our fallback to be only the actual placeholder.

Let us start with markup:

<div class="input">
  <input class="input-control" type="email" name="email" placeholder="Email" id="email" required />
  <label class="input-label" for="email">Email</label>
</div>

As before, the key is to first add styles for older browsers. We hide the label and set the color of the placeholder.

.input {
  height: 3.2em;
  position: relative;
  display: flex;
  align-items: center;
  font-size: 1em;
}

.input-control {
  flex: 1;
  z-index: 2; /* So that it is always "above" the label */
  border: none;
  padding: 0 0 0 1em;
  background: transparent;
  position: relative;
}

.input-label {
  position: absolute;
  top: 50%;
  right: 0;
  bottom: 0;
  left: 1em; /* Align this with the control's padding */
  z-index: 1;
  display: none; /* Hide this for old browsers */
  transform-origin: top left;
  text-align: left;
}

For modern browsers, we can effectively disable the placeholder by setting its color to transparent. We can also align the input and the label relative to one other for when the placeholder is shown. To that end, we can also utilize the sibling selector in order to style the label with respect to the state of the input.

.input-control:placeholder-shown::placeholder {
  color: transparent;
}

.input-control:placeholder-shown ~ .input-label {
  transform: translateY(-50%)
}

.input-control:placeholder-shown {
  transform: translateY(0);
}

Finally, the trick! Exactly like above, we override the styles for the label and the input for modern browsers and the state where the placeholder is not shown. That involves moving the label out of the way and shrinking it a little.

:not(*):placeholder-shown,
.input-label {
  display: block;
  transform: translateY(-70%) scale(.7);

}
:not(*):placeholder-shown,
.input-control {
  transform: translateY(35%);
}

With all the pieces together, as well as more styles and configuration options that are orthogonal to this example, you can see the full demo:

See the Pen CSS-only @supports for selectors demo by Jirka Vebr (@JirkaVebr) on CodePen.

Reliability and limitations of this technique

Fundamentally, this technique requires a selector that matches nothing. To that end, we have been using :not(*); however, its support is also limited. The universal selector * is supported even by IE 7, whereas the :not pseudo-class has only been implemented since IE 9, which is thus the oldest browser in which this approach works. Older browsers would reject our selector groups for the wrong reason — they do not support :not! Alternatively, we could use a class selector such as .foo or a type selector such as foo, thereby supporting even the most ancient browsers. Nevertheless, these make the code less readable as they do not convey that they should never match anything, and thus for most modern sites, :not(*) seems like the best option.

As for whether the property of groups of selectors that we have been taking advantage of also holds in older browsers, the behavior is illustrated in an example as a part of the CSS 1 section on forward-compatible parsing. Furthermore, the CSS 2.1 specification then explicitly mandates this behavior. To put the age of this specification in perspective, this is the one that introduced :hover. In short, while this technique has not been extensively tested in the oldest or most obscure browsers, its support should be extremely wide.

Lastly, there is one small caveat for Sass users (Sass, not SCSS): upon encountering the :not(*):placeholder-shown selector, the compiler gets fooled by the leading colon, attempts to parse it as a property, and when encountering the error, it advises the developer to escape the selector as so: \:not(*):placeholder-shown, which does not look very pleasant. A better workaround is perhaps to replace the backslash with yet another universal selector to obtain *:not(*):placeholder-shown since, as per the specification, it is implied anyway in this case.


Using Feature Detection, Conditionals, and Groups with Selectors originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/using-feature-detection-conditionals-and-groups-with-selectors/feed/ 3 277540
:not https://css-tricks.com/almanac/selectors/n/not/ https://css-tricks.com/almanac/selectors/n/not/#comments Wed, 07 Sep 2011 03:22:37 +0000 http://css-tricks.com/?page_id=14238 The :not() property in CSS is a negation pseudo class and accepts a simple selector or a selector list as an argument. It matches an element that is not represented by the argument. The passed argument may not contain additional …


:not originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The :not() property in CSS is a negation pseudo class and accepts a simple selector or a selector list as an argument. It matches an element that is not represented by the argument. The passed argument may not contain additional selectors or any pseudo-element selectors.

The ability to use a list of selectors as an argument is considered experimental, although its supported is growing at the time of this writing, including Safari (since 2015), Firefox (since December 2020), and Chrome (since January 2021).

/* the X argument can be replaced with any simple selectors */
:not(X) {
  property: value;
}

In this example we have an unordered list with a single class on the <li>:

<ul>
  <li></li>
  <li class="different"></li>
  <li></li>
</ul>

Our CSS would select all the <li> elements except the one(s) with a class of .different.

/* Style everything but the .different class */
li:not(.different) {
  font-size: 3em;
}

You could also do the same using pseudo classes which are considered a simple selector.

p:not(:nth-child(2n+1)) {
  font-size: 3em;
}

However, if we use a pseudo-element selector as our argument it will not produce the expected result.

:not(::first-line) { /* ::first-line is a pseudo element selector and not a simple selector */
  color: white;
}

Complex selectors

These are newer than the basic :not() selectors.

/* select all <p>s that are not descendants of <article> */
p:not(article *) {

}

This can get a little mind-bending with just a bit more nesting. For example:

h2:not(:where(article *, section *)) {
  ... 
}

/*
<article>
  <h2> No match! </h2>
</article>

<section>
  <h2> No Match! </h2>
</section>

<aside>
  <h2> Match! </h2>
</aside>
*/

Visual example

Visual representation of the varied uses of :not()

Specificity

The specificity of the :not pseudo-class is the specificity of its argument. The :not() pseudo-class does not add to the selector specificity, unlike other pseudo-classes. 

Negations may not be nested so :not(:not(...)) is never permitted. Authors should also note that since pseudo-elements are not considered a simple selector, they are not valid as an argument to :not(X). Be mindful when using attribute selectors as some are not widely supported as others. Chaining :not selectors with other :not selectors is permissible.

Browser support

The :not() pseudo class has been updated in the CSS Selectors Level 4 specification to allow an argument list. In CSS Selectors Level 3, it was only capable of accepting a single simple selector. As a result, browser support is a little divided between the Level 3 and Level 4 drafts.

Simple selectors

IEEdgeFirefoxChromeSafariOpera
9+AllAllAll12.1+All
Android ChromeAndroid FirefoxAndroid BrowseriOS SafariOpera Mobile
AllAllAllAllAll

Selector lists

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

Desktop

ChromeFirefoxIEEdgeSafari
8884No889

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
1081071089.0-9.2

More information


:not originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/almanac/selectors/n/not/feed/ 33 14238