More than a year ago I published
12 little-known facts about CSS (Habré
translation ), and to this day it was one of the most popular articles on SitePoint. Since then I have collected more interesting and small CSS tips for a new publication. We all know that every successful film should contribute to the release of the newfangled sequel, right?
Author of illustration SitePoint / Natalia Balska .So let's look at this year’s selection of dozens of obscure facts about CSS. I'm sure many of you know at least some of them, but you can let me know in the comments how many of the facts turned out to be new to you.
')
Translator's Note0. Yes, I saw a translation of the same article published a couple of hours ago. But my conscience will not allow me to remove the many days of work due to being late for a couple of hours :) in general, in your judgment.
1. The original article is replete with working demonstrations with CodePen. Habr, unfortunately, does not support insertions from similar resources, and I think it makes no sense to replace dynamic working examples with static images. Therefore, the article turned out to be a little “bald” sheet, but, I hope, interested readers will discover the missing examples from the links in a new window.
2. Although I have a direct bearing on the layout, the translation was large and not as simple as it seemed at first. Notes on errors, typos, terminology, etc. please send a personal message to habraposhta.
1. In the property border-radius
you can use the "slash" syntax
I already
wrote about this on SitePoint more than four years ago, but I think that many beginners and even some experienced developers are not aware of this possibility.
Believe it or not, the following code is valid:
.box { border-radius: 35px 25px 30px 20px / 35px 25px 15px 30px; }
If you have never seen this syntax, it may seem a bit confusing, so I’ll provide an explanation from the specification:
If the values are specified before and after the slash, then the values before the slash set the horizontal radius, and the values after the slash - vertical. If no slash is used, the values of both radii (both horizontal and vertical) are considered the same.
The specification also shows the following scheme:
In the explanation to the picture it says: "Two values of the
border-top-left-radius: 55pt 25pt
determine the curvature of the angle."
Thus, the use of a slash in the values of the
border-radius
property allows you to create asymmetrically curved corners (
note of the translator: rounds ). If you want to understand this in more detail, read my article (the link to which was cited above), or better see a convenient
interactive demonstration from MDN .
Most
border-radius
generators do not allow the use of these optional values. Of those that I found, the only generator from MDN supports the “slash” syntax.
2. The font-weight
property supports relativity keywords
Usually, when you see the description of the
font-weight
property, the value in it is either
normal
or
bold
. You could also see integer values with an increment of a hundred:
100
,
200
, etc. up to
900
However, there are two values that are often forgotten: the
bolder
and the
lighter
.
According to the specification, these keywords make the font fatter or thinner relative to the inherited value. The most important thing is that it works when you are dealing with a font that supports several degrees of “boldness”, which supports fonts that are thicker than regular
bold
and thinner than just normal text.
In syntax based on integer values,
700
means
bold
and
400
means
normal
. So, if your font supports a thickness of
300
, but not less, the
lighter
value will use a thickness of
300
if the inherited font thickness is
400
. If the font does not support a finer type (i.e., the default value of
400
is the thinnest), then the thickness will remain
400
, and the
lighter
value will have no effect on the text.
Look at the following
example .
In this example, I use the
Exo 2 font, which supports 18 different styles. My demo does not use italic styles, but the font supports them for each value from
100
to
900
.
The example includes 12 nested “box” elements with different
font-weight
values, including
bolder
and
lighter
, so you can see how this affects the “fatness” of the text in different cases of inheritance. Below the spoiler is the CSS from the example. Pay attention to the comments in the code, and remember that every next “box” element is nested in the previous one:
CSS from example .box { font-weight: 100; } .box-2 { font-weight: bolder; } .box-3 { font-weight: bolder; } .box-4 { font-weight: 400; } .box-5 { font-weight: bolder; } .box-6 { font-weight: bolder; } .box-7 { font-weight: 700; } .box-8 { font-weight: bolder; } .box-9 { font-weight: bolder; } .box-10 { font-weight: lighter; } .box-11 { font-weight: lighter; } .box-12 { font-weight: lighter; }
In this case, the key owl “bolder” and “lighter” set the
font-weight
to values
100
,
400
,
700
and
900
. With nine different styles, these keywords will never lead to values of
200
,
300
,
500
,
600
and
800
.
This happens because you tell the browser to select the next font in the series that is “fatter” or “thinner”. But the browser chooses not just the next option fatter or thinner, but the option of fatter or fatter relative to the current one. However, if the thinnest font style begins with a value of
300
(as in the
Open Sans font ), and the default value is
400
, then using the “lighter” keyword will set the
font-weight
to a value of
300
.
This may seem confusing, but you can play around with an example to understand how these keywords work.
3. The outline-offset
property
The
outline
property is well known for its convenience when debugging typesetting (the
outline of an element does not affect the surrounding elements in any way ). In the specification, however, the
outline-offset
property has also been added, which does exactly what its name implies - it allows you to set the margin indent from the element.
Example of outline-offset
.
In this example, move the slider left / right to see how this affects the contour indent from the element. In this case, the indent varies from
0px
to
30px
, but in CSS you can specify any indent. It should be remembered that although
outline
and a universal property (at the same time setting the color, style, and thickness of the outer border), it does not include
outline-offset
. Therefore, if necessary, the
outline-offset
each time you need to register separately.
The only negative
outline-offset
is that it is supported by all browsers except Internet Explorer (it does not even support IE 11).
4. CSS has table-layout
property
You will probably say: “Ha, as old as the world. I know about
display:table
. The simplest way to vertical centering. ” But this is not what I want to talk about. Notice, I said the
table-layout
property, not the
display
.
The
table-layout
property is not the easiest CSS feature to explain how it works. Therefore, let's look at the specification, and then consider an example. The specification reads as follows:
At the same time (fast) algorithm, the horizontal breakdown of the table does not depend on the content in the cells; depends only on the width of the table, the width of the columns and borders or the distance between cells.
This seems to be the first time that something is difficult to understand in the W3C specification ... Hah, just joked (
comment of the translator: in the original “LOL JK” ).
But seriously, as always a
living example will help us. In this demo table in CSS added
table-layout: fixed
. Click the button to turn this feature off / on.
In this example, you can see the advantage of using
table-layout: fixed
over
table-layout: auto
. Such an approach will not always be the best choice and is not always necessary, but it would not be bad to know about it when it comes to tables with cells of irregular width.
Last year, Chris Coyier wrote an
excellent article on table-layout
, so if you want to know more about this property, I advise you to read.
5. The vertical-align
property in table cells works differently than in other elements.
If you were creating websites in the mid-2000s and earlier or often HTML-letters for email lists, you probably assume that the
vertical-align
CSS property is analogous to the old
HTML4 attribute valign
, which is
no longer supported in
HTML5 .
But the
vertical-align
CSS property doesn't work the same way, especially with tables. This, in my opinion, is weird, but still better than if the property did not work in tables at all.
So what is the difference between applying a property to ordinary elements and to table cells?
If
vertical-align
does not apply to table cells, then follow these simple rules:
- only works with
inline
and inline-block
elements; - does not affect adjacent elements in the content, but affects the alignment of an element relative to adjacent
inline
and inline-block
elements; - font properties, such as
line-height
, and the size of adjacent inline
and inline-block
elements affect the property.
In
this example, the vertical-align
property is assigned to the
input
element. By clicking on the buttons you can set the property values written on the buttons. Notice how each value changes the position of the
input
element.
In general, this is a fairly simple demonstration of the property. For more in-depth analysis, read Christopher Aue last year’s
article .
When it comes to tables,
vertical-align
works quite differently. In this case, you apply the property to one or more cells, and the alignment of the content of the cells depends on the selected value.
CodePen example .
As shown in the example, only 4 values of the
vertical-align
property are applicable to table cells. In addition, the
baseline
value affects not only the cell to which it is affixed, but also the neighboring cells in the row of the table.
6. The pseudo-element ::first-letter
smarter than you thought.
The pseudo-element
::first-letter
allows you to stylize the first letter of any element and makes it possible to realize the effect of the
initial letter (
comment of the translator: I allowed myself to refer to the Russian-language wiki page ), which has been circulated in print for many years.
The good news is that browsers seem to have the same idea about the “first letter” of an element. I first read about this in a
tweet by Matt Andrews (Matt Andrews), although he clearly did not like this browser behavior. You can see his
example on CodePen .
It seems to me that the big four browsers work with this property in the same way, and this is cool, because I think this is the right behavior. It would be a little strange if the opening bracket was considered the first letter. In this case, it would be similar to the “first character” (first character), which could become an independent pseudo-class.
7. In HTML, you can use invalid characters as a separator in the list of element classes.
This approach was discussed
in 2013 by Ben Everard, and I think it’s worth a closer look at this topic.
Ben's publication talked about using a slash ("/") to split class lists in HTML into groups to make the code easier to read and understand. The author points out that although the slash is an invalid character, browsers will not stumble on it, but simply ignore it.
Suppose you have this HTML:
<div class="col col-4 col-8 c-list bx bx--rounded bx--transparent">
With slashes, it will look like this:
<div class="col col-4 col-8 / c-list / bx bx--rounded bx--transparent">
You can use any characters (both valid and invalid) as separators:
<div class="col col-4 col-8 ** c-list ** bx bx--rounded bx--transparent"> <div class="col col-4 col-8 || c-list || bx bx--rounded bx--transparent"> <div class="col col-4 col-8 && c-list && bx bx--rounded bx--transparent">
All such constructions work fine, you can test on
this demo .
Of course, these delimiters cannot be used as classes, so I call them "invalid." The following code will be disabled and will not apply styles to the element:
./ { color: blue; }
If you want to use such characters in class names, while maintaining their functionality, you can escape them by using
this tool . The previous example will work only if the CSS looks like this:
.\/ { color: blue; }
Delving into the details, I will say that Unicode characters do not need to be escaped, so you can use these crazy constructions:
<div class=" ★"></div>
With this CSS:
. { color: hotpink; } .★ { color: yellow; }
It is also possible to escape characters of this type, instead of directly inserting them. The following code is equivalent to the previous one:
.\2665 { color: hotpink; } .\2605 { color: yellow; }
8. The number of repetitions of animation can take fractional values.
You probably know that when using keyframe animations, you can use the
animation-iteration-count
property to set the number of animation repeats:
.example { animation-iteration-count: 3; }
The integer value in this case means that the animation needs to be repeated 3 times. But perhaps you are not aware that fractional values can be set:
.example { animation-iteration-count: .5; }
In this case, only half of the animation will start (it will stop at half past the first iteration). Let's
look at an example in which two balls are animated. At the top ball, the repeat counter is set to “1”, and at the bottom one to “0.5”.
Interestingly, the repeat count does not depend on the property / value that is being animated. In other words, if you are animating some 100 pixels, this does not mean that the animation will stop at 50 pixels on half of the replay. The previous example uses the timing function
linear
, which ensures that the second ball stops half way.
Here are two more animations, but here the timing function
ease
already used:
an example . Please note that now the second ball also passed halfway through the animation. I repeat, this happens because of the different timing functions.
If you understand the timing function, you will understand why the ball stops at the same position as at
linear
with
ease-in-out
. Play around with different fractional values and timing functions to see how this affects the result.
9. Animation
may not work due to the name of the animation.
Some developers have discovered this by chance on their own experience, although there is a warning about this in the specification. Suppose you have the following animation code:
@keyframes reverse { from { left: 0; } to { left: 300px; } } .example { animation: reverse 2s 1s; }
Notice, for animation, I use the name
reverse
. At first glance, the code looks working, but notice what happens if we use it in a live
example .
Animation does not work, since “reverse” is a reserved keyword for the
animation-direction
property. This will happen with any animation whose name matches the reserved keywords used in the universal (short) recording method. With a detailed recording form, with separate indication of the
animation-name
and other parameters, the animation will work.
The names of the animations that can break the short form of the record include the
names of the timing functions , such as
infinite
,
alternate
,
running
,
paused
, etc.
10. You can select a range of items.
I do not know who first used this opportunity, but I first learned about it from
this example from Gunnar Bittersmann. Let's say you have a numbered list of 20 items and you want to select items 7 through 14 inclusive. Here's how to do this with one selector:
ol li:nth-child(n+7):nth-child(-n+14) { background: lightpink; }
See the
demo of the selector .
Update: As noted in the comments, in Safari there is a bug, because of which this technique does not work. Fortunately, the solution proposed by Matt Pomaski seems to work: just expand the pseudo-class chain to get the ol li:nth-child(-n+14):nth-child(n+7)
selector ol li:nth-child(-n+14):nth-child(n+7)
. In the nightly builds of WebKit, there is no such bug, so over time, and in Safari, this design will work fine.This code uses a bunch of pseudo-classes with expressions. Although expressions may seem confusing, you can see the selection of elements in the numbers used in these expressions.
How it works: In the first part of the bundle, the expression says “choose the 7th element and each after it”. The second part says “choose the 14th element and each one before it”. But since the selectors are in a bundle, each restricts the sample area of the other. So the second part of the bundle does not allow the first to get out of the 14th element, and the first part does not allow the second to go down in the sample below the 7th element.
For a more detailed study of these types of selectors and expressions, you can read
my old post on this topic .
11. Pseudo-elements can be applied to some single tags.
Perhaps you, like me, at some point tried to apply pseudo-elements to images or form elements. This will not work, because pseudo-elements do not work with replaceable elements. I think many developers assume that this applies to all single tags (not having a closing tag). But it is not.
You can apply pseudo-elements to
some single tags that are not replaceable elements. This also applies to the
hr
element, as can be seen from
this example .
The shaded area in this example is the horizontal essay (
hr
element), and both the pseudo-elements
::before
and
::after
applied to it. Interestingly, I was not able to get the same result with
br
, although it is an indispensable one-tag element.
You can also add pseudo-elements to the
meta
and
link
elements if you are abnormal enough to make them
display: block
, as shown in the
following example .
12. Some values in attribute selectors are case-insensitive.
In conclusion, consider one small obscurity. Suppose you have the following HTML:
<div class="box"></div> <input type="email">
You can apply styles to each of these elements using attribute selectors, like this:
div[class="box"] { color: blue; } input[type="email"] { border: solid 1px red; }
Such styles work fine. And what if you do this?
div[class="BOX"] { color: blue; } input[type="EMAIL"] { border: solid 1px red; }
Notice that the attribute values are now uppercase. In this case, styles will not be applied to the
.box
element, since the
class
attribute is case-sensitive. On the other hand, email styles are applied to the field because the values of the
type
attribute are not case sensitive. There is no discovery here, but perhaps you did not know about it.
People it's time to wrap up
At that moment the curtain goes down, and the hope-not-too-crappy sequel ends.
It is felt that every week I stumble upon some small CSS of interestingness and study them, and I hope that something from the above described has been cognitive for most of you. What are your favorite little known CSS tricks or techniques? Do you know CSS features or features that you consider to be little-known but well supported browsers? Share them in the comments.