One of the major thorns in my side when working on CSS crimes copost creation tools has been ensuring that they look good on everyone's screens. In normal CSS authoring, you'd use @media rules to provide "responsive" styles that adjust themselves based on the width of the user's viewport. Once a user's screen or window size goes below certain "breakpoints", elements rearrange themselves or change their sizing logic to accommodate. But because you can't write a top-level stylesheet in a copost, that won't work for us.
I've figured out a way to work around this, though. CSS Values and Units Level 3 introduced the vw unit, which is a length that measures exactly 1% of the size of the user's viewport. Using this and some clever math, we can create inline breakpoints (with a few substantial caveats). For example, let's take the breakpoint 768px from Cohost's own CSS. Most tablets and desktops are wider than 768px, while phones (in vertical orientation) are universally narrower, so it's nice to selecting for desktop versus mobile users. We can then write our inline breakpoint like this:
min(max((100vw - 768.1px)*9999, <mobile value>), <desktop value>)
This expression will essentially return <mobile value> on mobile devices and <desktop value> on desktop devices. Great! But how does it work? Let's break it down:
- Since
1vwis 1% of the viewport width,100vwis the width of the entire viewport. 100vw - 768.1pxis a positive number if the viewport is larger than768px, and negative if it's smaller or equal to768px. (We add the.1to ensure that we don't get weird behavior for exactly-768px-wide viewports.)- We multiply this by
9999to get a very large negative number for mobile devices and positive number for desktop devices. (Note that if this is five 9s Firefox shits the bed for some reason, so: exactly four 9s.) - Finally, we use
max()andmin()to convert this to the actual numbers we want, since<mobile value>will always be larger than the very negative number and<desktop value>will always be smaller than the very positive number.
As I mentioned, there are a few caveats:
-
This only works for numeric values. You can't use this to set an element to
display: noneon mobile, for example. To make the demo above, I had to set thewidthto0pxinstead. -
It specifically only works for lengths. Calculation expressions like
min()andmax()have to have comparable units, so you can't use this to set other types of value like opacity or timing. -
As written
<mobile value>must be less than<desktop value>, but you can fix this by changing the order of the subtraction expression.
I plan to use this to update my grid generator to be more intelligent about font choice selection pretty soon, and I hope other people will find it useful as well.
