Build a CSS Ruler
Mads Stoumann
Posted on September 27, 2021
I'm currently working on a project, where an editor can easily edit breakpoints, using a group of color-coded, stacked <input type="range">
-controls, and a bit of JavaScript:
While this works, it's easier to visualize the breakpoints, if combined with a ruler:
At first, I hardcoded a ruler, using pixels — but then I thought: “What if the editor wants to define the breakpoints in em
or ch
— or some other unit?”
Let's look into how we can create a configurable ruler, using CSS backround-image
, a bunch of variables — and only a tiny bit of JavaScript for a visual editor.
Our ruler will have two sets of “ticks” — low and tall (we'll look into the numbers later):
Both sets of ticks have some initial Custom Properties:
.ruler {
/* Low ticks */
--ruler1-bdw: 1px;
--ruler1-c: #BBB;
--ruler1-h: 8px;
--ruler1-space: 5;
/* Tall ticks */
--ruler2-bdw: 1px;
--ruler2-c: #BBB;
--ruler2-h: 20px;
--ruler2-space: 50;
}
With these properties, we can create a dynamic background-image
:
.ruler {
background-image:
linear-gradient(90deg, var(--ruler1-c) 0 var(--ruler1-bdw), transparent 0),
linear-gradient(90deg, var(--ruler2-c) 0 var(--ruler2-bdw), transparent 0);
}
However, without background-repeat
and background-size
, we're not seeing anything that resembles a ruler!
.ruler {
background-repeat: repeat-x;
background-size:
calc(var(--ruler-unit) * var(--ruler1-space)) var(--ruler1-h),
calc(var(--ruler-unit) * var(--ruler2-space)) var(--ruler2-h);
}
And that's almost it! We just need to add background-attachment: fixed
, so the ruler will stay in place, when we're scrolling!
Adding numbers:
For the numbers, we'll create a list:
<ul class="ruler-x">
<li></li><li></li> <!-- repeat -->
</ul>
Each blank <li></li>
will be a number in our ruler. The number will be aligned to the bottom of the tall “ticks”:
.ruler-x {
color: var(--ruler-num-c);
counter-reset: d 0;
display: flex;
font-size: var(--ruler-num-fz);
height: var(--ruler2-h);
inset-block-start: 0;
inset-inline-start: calc(var(--ruler-unit) * var(--ruler2-space));
line-height: 1;
list-style: none;
margin: 0;
opacity: var(--ruler-x);
overflow: hidden;
padding: 0;
position: fixed;
width: 100%;
}
We'll use a CSS counter
to fill out the numbers, based on the --ruler2-space
-property:
.ruler-x li {
align-self: flex-end;
counter-increment: d var(--ruler2-space);
flex: 0 0 calc(var(--ruler-unit) * var(--ruler2-space));
}
.ruler-x li::after {
content: counter(d);
line-height: 1;
padding-inline-start: var(--ruler-num-pi);
}
Creating an Editor
Now, let's create a small editor for our ruler.
We'll use a small JavaScript to update the Custom Properties:
app.addEventListener('input', (e) => {
const input = e.target;
const value = input.type === 'checkbox' ? (input.checked ? 1 : 0) : input.value;
document.body.style.setProperty(input.name, value+(input.dataset.suffix||''));
})
In HTML, add <input>
s to <form id="app">
, using name
for the property to set, value
for the value (surprise!) and data-suffix
to add any suffix to the value:
<input type="range" name="--ruler1-h" value="8" data-suffix="px">
Repeat for all the properties, you want to be editable.
Demo
Here's a Codepen, where I've added a vertical ruler and an editor, using the technique described above (if you're on iOS, open it full-screen to avoid iframe scrolling-issues):
Bonus: right-to-left
If you want to use the y-axis
-ruler with rtl
, add a small snippet of CSS:
[dir="rtl"] .ruler {
background-position: 100% 0;
}
Cover-image from pexels.com
Posted on September 27, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.