Nowadays, we can do better:
```
box-shadow: 0 1px 2px
rgb(from currentcolor r g b/ .65)
```
Cross-browser since September 2024.
#tinyCSStip #CSS
Latest posts tagged with #tinyCSStip on Bluesky
Nowadays, we can do better:
```
box-shadow: 0 1px 2px
rgb(from currentcolor r g b/ .65)
```
Cross-browser since September 2024.
#tinyCSStip #CSS
No need to multiply by 9999, nest min() & max() now that we have sign()!
We can get the sign of the difference
--sgn: sign(100vw - var(-cutoff))
a bit value (0 if sign is -1 or 0, 1 otherwise)
--bit: round(down, .5*(1 + var(--sgn)))
finally
border-radius: calc(var(--bit)*8px)
#tinyCSStip #CSS
Here's my #tinyCSStip:
.my-elem {
background-size: auto 100%;
height: 1em;
width: (image's literal aspect ratio)em;
display: inline-block;
font-size: 10em;
}
/* ❌ DON'T ❌ */ .my-elem { background-image: url(my-image.jpg); background-size: cover; background-position: center center; /* this is pointless, nothing repeats when using cover */ background-repeat: no-repeat; } /* ✅ DO ✅ */ .my-elem { /* if only one background-position is specified, * the other defaults to 50% (= center) */ background: url(my-image.jpg) 50%/ cover }
Because I often see this and it's a major #CSS pet peeve of mine, makes me want to scream "do you even understand what `cover` does?" at the screen every time...
#tinyCSStip
Also, #tinyCSStip I've never shared on bsky 🦋 before.
The `aspect-ratio` property relates to `box-sizing`.
Let's say we have `aspect-ratio: 4/ 3`.
By default, it's the aspect ratio of the `content-box`.
But if we set `box-sizing: border-box`, `4/ 3` becomes the aspect ratio of the `border-box`.
.container { container-type: inline-size } .item { background: #335c67; @container ((width > 220px) and (width < 388px)) or (width > 580px) { background: #e09f3e /* this WORKS cross-browser!!! */ } /* equivalent to: * @container (width > 220px) and (width < 388px) { background: #e09f3e } @container (width > 580px) { background: #e09f3e }/**/ }
#tinyCSStip We can have boolean logic in container queries!
And this works cross-browser!
Live test on @codepen.io: codepen.io/thebabydino/...
More info on @developer.mozilla.org: developer.mozilla.org/en-US/docs/W...
#CSS
``` .my-elem { /* ❌ DON'T ❌ */ /* if you later need to make then both 4px or teal, * then you need to make changes in two places */ border-top: solid 8px gold; border-bottom: solid 8px gold; /*✅ DO ✅ */ border: solid gold; border-width: 8px 0; /* alternatively, for top and bottom */ border-block: solid 8px gold; /* or for left and right */ border-inline: solid 8px gold; } ```
#tinyCSStip Want the same border, but only for two edges, not for the others?
Don't set borders on the two edges to the same value, set border, then override border-width. If you later need to make the border thicker or thinner or pink or green, you only need to make that change in one place. #CSS
Screenshot of demo with gradient cards, all showing left to right gradients, vibrant at the top of the card, but getting progressively more and more desaturated as we go towards the bottom.
.card { /* relevant code for the effect */ background: linear-gradient(90deg, var(--stop-list)), linear-gradient(#0000, grey); background-blend-mode: luminosity; /* other styles */ aspect-ratio: 3/ 2; border-radius: .5em; box-shadow: 2px 2px 5px 1px #040404 }
And here's a cards demo with a cool, yet very simple trick: these left to right gradients are vibrant at the top, but then progressively get more and more desaturated going down, until fully grey.
Live on @codepen.io codepen.io/thebabydino/... - only 2 CSS declarations necessary!
#CSS #tinyCSStip
Diagram of how browsers apply filter and clip-path when they’re set on the same element. First the drop-shadow() filter is applied on the initial rectangular box, then the element with drop-shadow() is clipped, cutting out the drop-shadow() too.
Screenshot of the linked demo showing how applying the filter on the parent of the clipped (pseudo-)element can solve the problem if this parent has no other visible parts (borders, backgrounds, shadows).
#tinyCSStip `clip-path` or `mask` are applied after `filter`.
This means we cannot clip/ mask, then add a `drop-shadow()` on the same element for the clipped/ masked shape.
We need to apply the `filter` on a parent of the clipped/ masked (pseudo-)element.
codepen.io/thebabydino/...
#CSS #filter
Old CSS ``` .my-elem { animation: glow 5s ease-in-out infinite } /* repeating most of the shadow so many times */ @keyframes glow { 0% { text-shadow: 0 0 5em red /* hsl( 0 100% 50%) */ } 16.7% { text-shadow: 0 0 1em yellow /* hsl( 60 100% 50%) */ } 33.3% { text-shadow: 0 0 5em lime /* hsl(120 100% 50%) */ } 50% { text-shadow: 0 0 1em cyan /* hsl(180 100% 50%) */ } 66.7% { text-shadow: 0 0 5em blue /* hsl(240 100% 50%) */ } 83.3% { text-shadow: 0 0 1em magenta/* hsl(300 100% 50%) */ } 100% { text-shadow: 0 0 5em red /* hsl(360 100% 50%) */ } } ``` New CSS ``` @property --hue { syntax: '<angle>'; initial-value: 0deg; inherits: false } .my-elem { /* no repetition */ text-shadow: 0 1px calc(3em + 2em*cos(var(--hue))) hsl(var(--hue) 100% 50%); animation: hue 5s linear infinite } @keyframes hue { to { --hue: 1turn } } ```
#tinyCSStip Simplifying animations with variables and mathematical functions.
Same result, just not writing almost the same `text-shadow` a bunch of times in a bunch of keyframes.
Live test on @codepen.io: codepen.io/thebabydino/...
#CSS #Maths
@property --f { syntax: '<number>'; initial-value: 1; inherits: true } .scale { scale: var(--f); animation: scale 2s ease-in-out infinite alternate; /* no need for another animation on ::before to revert scale */ &::before { scale: calc(1/var(--f)) } } @keyframes scale { to { --f: .5 } }
#tinyCSStip
Revert animated parent transform (like a scale or skew) on child without an extra animation using registered custom properties.
codepen.io/thebabydino/...
#CSS
#tinyCSStip
🚫 DON'T use layered text-shadows for text outlines just because text-stroke is broken (bsky.app/profile/anat...), they are going to produce ugly corners, thickened roundings and angled lines.
✅ DO: use `paint-order: stroke fill` instead!
#CSS #typography
Screenshot showing the interactive demo showing that setting a `border-image` on an element with `border-radius` makes the `border-radius` be ignored.
Screenshot of the solution when the desired corner rounding is not bigger than the border-width: ``` border: solid $r; border-image: linear-gradient(90deg, purple, orange) 1; clip-path: inset(0 round $r) ```
Know how border-image & border-radius don't play nice together?
(interactive codepen.io/thebabydino/...)
#tinyCSStip there's a workaround IF corner radius ≤ border-width: use inset() clip-path + a round value!
clip-path: inset(0 round $r)
@codepen.io demo: codepen.io/thebabydino/...
#CSS
Also, those letters in the squares? #CSS counters!
```
.item { counter-increment: c }
.item::after { content: counter(c, upper-alpha) }
```
#tinyCSStip
The code and the live result. A dashed border framed by inner and outer box-shadows, all on top of a background is all that's needed for the effect.
#tinyCSStip Create a fancy double border with dashes in between without any pseudos and with minimal #CSS!
The relevant code is just 3 simple CSS declarations!
Live demo on @codepen.io: codepen.io/thebabydino/...
Code illustrating the old solutions (setting all four inset longhands or two inset longhands plus dimensions) vs. the much simpler (1 declaration instead of 4) inset shorthand (`inset: 0` is all that's needed). ``` /* want to make pseudo cover parent's entire padding-box */ .parent { position: relative; &::after { content: ''; position: absolute; /* ❌ DON'T do this 😵 */ top: 0; left: 0; height: 100%; width: 100%; /* ❌ DON'T do this either 😵 */ top: 0; right: 0; bottom: 0; left: 0; /* ✅ instead, DO! 😻 */ inset: 0 /* 👍 simpler & has been well-supported for YEARS 🥳 */ } } ```
#tinyCSStip if you want to make an absolutely positioned pseudo cover its parent's entire `padding-box`, use `inset: 0`!
(love grid for stacking/ full coverage too, but there are differences between how the two solutions work and there are cases when absolute positioning is still preferable)
#CSS
Ugly (1px misalignment issues) checkerboard edges.
Perfect checkerbox edges when every square is an integer number of pixels.
#tinyCSStip Want to avoid ugly checkerboard edges when the pattern size --s depends on viewport?
Round it to be a multiple of 2px so every square edge is an int number of pixels!
--s: round(10vmin, 2px);
background:
repeating-conic-gradient(red 0% 25%, tan 0% 50%)
0 0/ var(--s) var(--s)
#CSS
Code from linked CodePen demo.
#tinyCSStip
Pretty sure I've posted about this before, but a quick search at this hour didn't find it, plus saw someone ask about it yet again¹, so... fixed aspect-ratio box within variable size container!
Live on @codepen.io codepen.io/thebabydino/...
¹here www.reddit.com/r/css/commen...
#CSS
Screenshot of images with gradient/ pattern borders: a plain purple at the top to gold at the bottom gradient border, a hearts on a transparent background pattern border, a "cicada curtains" effect gradient border, a stars on a transparent background pattern border.
Code for the first two examples in the linked demo.
Code for the last two examples in the linked demo.
#tinyCSStip
What's the point of setting background on an img anyway? 🤷
Well, it's useful if we want a border pattern only possible with multiple gradients (border-image only allows one)/ if we also want to have rounded corners (border-image + border-radius = 💩).
codepen.io/thebabydino/...
#CSS
mask: conic-gradient(red 0 0) no-clip subtract, var(--excluded-area)
Screenshot of the linked demo. Shows 4 examples in 4 cases: no mask, mask without mask-clip: no-clip and mask with mask-clip: no-clip. In the first case, the blur resulting from a filter, box-shadow and a pseudo can be seen outside the element's border-box. In the second case, we have an area inside the element masked out and all of the above that's outside the element's border-box is cut out too.In the third case, we have an area inside an element, but the blur, box-shadow and pseudo are still visible outside the element's border-box.
#tinyCSStip
Ever want to mask something out of an element, but not cut out blur or box-shadow or a pseudo outside the element's border box? 🤔
Well, subtract whatever you want masked out from a fully opaque layer with `mask-clip` set to `no-clip`!
@codepen.io demo codepen.io/thebabydino/...
#CSS
[type=range] { /* styles for WebKit browsers */ } @supports selector(::-moz-range-track) { [type=range] { /* styles for Firefox */ } }
#tinyCSStip
Range input browser inconsistencies may mean needing different styles for different browsers. Possible for track & thumb via different pseudos, but what about the actual range input?
Well, `@supports selector()` to the rescue!
Live test on @codepen.io codepen.io/thebabydino/...
#CSS
The two options for getting a semitransparent version of currentColor: box-shadow: 0 1px 2px rgba(from currentColor r g b / .35); box-shadow: 0 1px 2px color-mix(in srgb, currentColor 35%, #0000);
#tinyCSStip
Want the shadow of an element or some other visual to be a semitransparent version of the `currentColor`, which was given as a hex or keyword value?
No need to convert to rgb() or hsl() anymore!
#CSS
Screenshot showing various options, either with filter() on the background image or: background: url(cat.jpg), linear-gradient(135deg, grey 50%, #0000 0); background-blend-mode: luminosity
#tinyCSStip Want a background-only & maybe partial, just for a certain area grayscale()-like effect?
background-blend-mode: luminosity (or color if layers need to be reversed) to the rescue! This uses image luminosity & grey saturation (0%).
In the future, filter() function should also work.
#CSS
Screenshot of a demo with two alpha controls and comparative side by side results of the two methods.
#tinyCSStip If you don't have any text content, borders or shadows, the following give the exact same visual result:
.i {
opacity: $a1;
background: rgba($c, $a0)
}
.o { background: rgba($c, $a0*$a1) }
(because I saw the first used for an image overlay to make it more transparent)
#CSS
#tinyCSStip
How varying clip-path: inset() from the right element edge can help with a left to right reveal effect
✨ when this inset is 100%, all gets cut off
✨ when this inset is 0%, nothing gets cut off
Interactive illustration codepen.io/thebabydino/... + 🆒 pure #CSS on scroll use case 👇
Code illustrating the problem. /* DON'T ❌ */ @keyframes b { 0% { color: tan } 49.99999% { color: tan } 50.00001% { color: red } 100% { color: red } } p { animation: b 2s infinite } /* DO ✅ */ @keyframes b { 50% { color: red } } p { color: tan; animation: b 2s steps(1) infinite }
#tinyCSStip Don't use many decimals in keyframe percentages to abruptly change a value. That's what the `steps()` timing function is for!
#CSS
#tinyCSStip Want your page background to contain an integer number of dots?
Use `background-repeat: space`! This inserts a bit of space in between background repetitions so we have an integer number of them. Well-supported for ages. 🥳
Live on @codepen.io codepen.io/thebabydino/...
#CSS #pattern
We have a structure with multiple sections inside the body, each section containing a text box and an image and we want the text box and the image to be two squares side by side, alternating positions depending on section parity IF there is enough room for the two squares to have an edge of at least 150px. A container query on the body works better than a media query here because the container query makes it depend on the body's content-box width because this is the viewport width minus scrollbars IF we have any (we cannot know).
#tinyCSStip Container queries on the body? Why, when media queries have better support?
Well, container queries make it an IF depending on the width of the body's content-box.
That is, subtracting the scrollbar IF we have one (we can't know).
@codepen.io demo codepen.io/thebabydino/...
#CSS
Regular hexagon with circumradii drawn to all its vertices. This splits it into 6 equilateral triangles and we can see the box that tightly fits this regular hexagon has the same aspect ratio as an equilateral triangle, as it fits two equilateral triangle edges along its width and two equilateral triangle heights along its height.
CSS to create a regular hexagon. Set width to a custom property var(--d). Set aspect ratio to 1/sin(60deg). Give it a background just so we can see something on the screen. Set a clip-path to a polygon whose points are located at 25% and 75% on the top edge of the containing rectangular box, in the middle of the right edge of this box, at 75% and 25% on the bottom edge of this box and in the middle of the left edge of this box.
Shows a CSS-created hotpink regular hexagon on the left and the Firefox DevTools panel open on the right. The code for this hexagon can be seen under the Rules tab in the Inspector. Before the `polygon()` function, there's a button toggling the CSS Shape Editor in Firefox DevTools. On clicking it, hollow circles show at the coordinates of the points listed inside the `polygon()` function. On hovering any of these coordinates inside the function, the corresponding circle fills up. This way, we can see what coordinate corresponds to what point.
#tinyCSStip/ fun fact: same aspect ratio is also what we need for a regular hexagon because that can made up of only equilateral triangles!
We just need more points for the clip-path (6 for a hexagon vs. 3 for a triangle).
#CSS #Maths