I encountered an odd problem in the app I'm developing. I'm originally using svelte and tailwind css, however I have reproduced the issue in pure html/css.
In order to achieve a non-scrolling header, I followed some examples I have seen online: Set the body's size to 100vw x 100vh, and set overflow to be hidden, then within that add my header, and my main, making sure overflow is set to auto on the main.
This works great, in my content I have some radio buttons, which also works fine until I add the sr-only class from tailwind.
From the moment I add this class, clicking a label that was originally outside the viewport seems to scroll my unscrollable body, causing the layout of the site to be broken,
I have managed to reproduce in jsfiddle: https://jsfiddle.net/ax7t6ngf/ (code may seem long, but it's just the same element duplicated many times to have some contents to scroll)
*,
::before,
::after {
box-sizing: border-box; /* 1 */
border-width: 0; /* 2 */
border-style: solid; /* 2 */
border-color: #e4e4e7; /* 2 */
}
html {
line-height: 1.5;
tab-size: 4;
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}
nav {
color: white;
background-color: black;
width: 100%;
padding: 1rem;
}
body {
overflow: hidden;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
main {
display: flex;
flex: 1;
padding: 1rem;
overflow: auto;
background-color: #f3f4f6;
gap: 0.5rem;
}
.narrow-container {
max-width: 32rem;
margin: auto;
}
.font-bold {
font-weight: 700;
}
.italic {
font-style: italic;
}
.button-group {
display: inline-flex;
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
box-shadow: black;
}
.radio-button-group {
display: flex;
background-color: white;
text-align: center;
padding: 1rem;
border-width: 1px;
justify-content: center;
align-items: center;
flex-direction: column;
font-weight: 500;
font-size: 0.75rem;
}
.radio-button-group:hover {
background-color: lightgrey;
}
.radio-button-group:focus-within{
color: red;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>
<body>
<header>
<nav>
Header
</nav>
</header>
<main>
<div class="narrow-container">
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">Some Question</p>
<p class="italic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis. Nulla nec purus feugiat, vestibulum
mi nec, ultricies metus. Integer sit amet semper turpis.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input class="sr-only" type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input class="sr-only" type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
<div>
<p class="font-bold">This one doesn't seem to break everything.</p>
<p class="italic">
The only difference is the lack of "sr-only" class on the input.
</p>
<div class="button-group" role="group">
<label class="radio-button-group">
<input type="radio" value="1">
<span>Disappointing</span>
</label>
<label class="radio-button-group">
<input type="radio" value="2">
<span>Under Expectations</span>
</label>
<label class="radio-button-group">
<input type="radio" value="3">
<span>As Expected</span>
</label>
<label class="radio-button-group">
<input type="radio" value="4">
<span>Above Expectations</span>
</label>
<label class="radio-button-group">
<input type="radio" value="5">
<span>Exceptional!</span>
</label>
</div>
</div>
</div>
</main>
</body>
</html>
To see the problem:
It is possibly Chrome-related, when I try in Firefox there seems to be no problem.
I've tried different combinations of layouts, and I wonder if maybe I hit a bug in Chrome? Or if I'm the one doing something inherently wrong, I'm not a CSS expert.
I have found this other question: sr-only class causing page scroll which seems slightly related, and points to a chromium bug https://issues.chromium.org/issues/40734994 which has been closed since.
I have found that taking out the position: absolute
from the sr-only
class resolves the problem, but that class is from tailwind, and every other implementation I find also uses position: absolute
so I'm a little nervous just removing it.
Upon observing the behaviour closer and modifying the sr-only
class, I have noticed that the way my elements were set-up, the hidden radios ended up on a "layer" lined up with my labels, except this "layer" would not scroll when the underlying div was scrolling, resulting in some of these elements being outside the canvas, and staying there.
Whenever clicking the label corresponding to one of the invisible radios outside the canvas, thus setting the focus on that element, Chrome attempts to bring the element into view. Since scrolling the element meant to be scrolled wouldn't move those, chrome scrolls the body, causing the whole thing to fall apart.
What I have found out is that making my main
position:relative
causes the "layer" of radios to now scroll with the rest of the page. When Chrome now scrolls to bring the radio into view, it does so using the intended scrollbar and nothing breaks.
As per https://dev.to/neshaz/css-position-relative-vs-position-absolute-26ok:
Absolute positioning is done relative to the first relatively (or absolutely) positioned parent element. In the case when there is no positioned parent element, the element that has position set to absolute will be positioned related directly to the HTML element (the page itself).
I was indeed being bad at CSS =)