Search code examples
cssfrontendaccessibilityweb-frontend

sr-only class causing page scroll


I want to make some content available to screen readers but not visible on the page. Taking it off the page result in screen readers not announcing it, so I'm using a common hacky workaround, the sr-only class, used for instance by Bootstrap. Here's Kitty Giraudel's version:

.sr-only {
  border: 0 !important;
  clip: rect(1px, 1px, 1px, 1px) !important;
  -webkit-clip-path: inset(50%) !important;
  clip-path: inset(50%) !important;
  height: 1px !important;
  overflow: hidden !important;
  padding: 0 !important;
  position: absolute !important;
  width: 1px !important;
  white-space: nowrap !important;
}

The problem is with the position: absolute rule, which necessitates a parent with position: relative. Without it, the invisible content may end up at the bottom of the page and cause the browser to add scrollbars. I don't like having to have to add that position: relative rule on top of the sr-only class. It can easily be forgotten or accidentally removed. It would be easier if adding the class was the only needed step, which seems possible by simply adding top: 0 to these rules. But I'm a little nervous tweaking with such ancient wisdom. Is there a reason why it's not commonly done this way? Am I missing a potential issue with top: 0?


Solution

  • Short Answer

    No, do not use top: 0

    Longer Answer

    First the issue you linked in the comments is using a very broken (and old as far as I can tell) screen reader only class, I think it has been updated (and if not then that just reinforces my opinions on using Font Awesome! 🤣).

    The screen reader class you linked is identical to the visually hidden text class I created / use (which just shows if two of us came up with the same thing it might just be right!) and should not cause the issue described as it uses clip-path: inset(50%).

    clip-path: inset(50%) effectively makes the element 0px high and 0px wide, so you should never get any overflow issues because of it.

    Also the scroll bar issue tends to be caused by the margin: -1px part (which you notice we aren't using in our classes), but without something to test against I cannot confirm that is the case here.

    As for adding top: 0 don't do this - you are indeed wise to not mess with old wisdom.

    The second you start moving the position of the element some screen readers will try and compensate for the positioning (thinking that you are a bad developer and using absolute positioning to change the order of things on the page instead of changing DOM order), resulting in strange reading orders.

    I have used the class I linked for 2 years now without ever seeing any unexpected scroll bars so you should be safe.

    With all that being said, if you do manage to put together a codepen / fiddle etc. that demonstrates the issue you described with the class I recommend or the class in your question then please let me know as that is something I would want to address!

    Final thoughts

    In the bug report you linked in the comments, do not do as the final message suggests:

    1. Size the element such that it is 0xN, or Nx0 (e.g. "width: 0" or similar).
    2. Make the element "display: none".
    3. Surround the element in a 0x0 div which is also "position: absolute".

    All 3 of the above options would render the text completely invisible to a screen reader user (remove the element from the accessibility tree) and completely break the point of using a screen reader only class.

    Options 4 and 5 are feasible options though:

    1. Make "viewport-router" a containing block (e.g. "position: relative" or similar).
    2. Change the "viewport-main" to "overflow-y: hidden" or similar.