Skip to content

Ensure code can be scrolled past Ferris without being obscured - #4834

Open
benedictjohannes wants to merge 2 commits into
rust-lang:mainfrom
benedictjohannes:fix-ferris-code-overlap
Open

benedictjohannes wants to merge 2 commits into
rust-lang:mainfrom
benedictjohannes:fix-ferris-code-overlap

Conversation

@benedictjohannes

Copy link
Copy Markdown

Fixes #2893.
Alternative to #4540.

Problem

On mobile and narrow viewports, Ferris (.ferris-container) is absolutely positioned over the top-right corner of code blocks. When code lines are long and horizontally scrolled, the ends of lines slide directly under Ferris, obscuring code and making it unreadable.

Solution

Add right padding to code blocks inside pre elements that contain a Ferris badge (pre:has(.ferris-large) and pre:has(.ferris-small)).

/* Ensure code can be scrolled past Ferris without being obscured */
pre:has(.ferris-large) > code {
  padding-right: calc(4.5em + 1.5rem);
}

pre:has(.ferris-small) > code {
  padding-right: calc(2.3em + 1.5rem);
}

This guarantees that when scrolling horizontally to the end of a line, the code stops before the Ferris icon rather than slipping underneath it.

Comparison with #4540

Compared to PR #4540 which introduces ~70 lines of JavaScript to walk text nodes, parse line endings, and perform asynchronous bounding-box collision detection, this method has:

  • Zero DOM manipulation: Keeps HTML and AST untouched, preserving syntax highlighting and standard text copy-paste.
  • Pure CSS: Uses native browser layout with :has() (supported across all major browsers since 2023).
  • Zero runtime overhead: No layout recalculations or setTimeout delays.

Visual Comparison (Mobile Viewport)

Screenshot_Ferris_Compare

@NeatNit

NeatNit commented Sep 27, 2026

Copy link
Copy Markdown

This has my blessing (I am the author of #4540), but I have to note, the reason I went through the trouble of doing the JS with all that entailed is to prevent adding padding when it isn't actually needed. For example: https://doc.rust-lang.org/stable/book/ch02-00-guessing-game-tutorial.html#comparing-the-guess-to-the-secret-number

Screenshot_20260927_174131_Firefox

In this case, Ferris isn't hiding any code so padding is not needed. This PR will add padding anyway, "just to be safe" and to avoid having to determine if this is the case.

It's harmless, but I was nitpicky enough to want to find a way around it.

@benedictjohannes

Copy link
Copy Markdown
Author

@NeatNit Thanks for the endorsement and for sharing the context behind that decision!

I agree with your observation: with pure CSS, the padding applies across the entire code block, so code blocks with long lines lower down (past Ferris) will receive a right-side buffer when scrolled, regardless of whether it's strictly needed. This is why I labeled my PR as an alternative to your approach, not necessarily a superior one.

With that said, when the Ferris padding is applied, it doesn't harm readability, it simply adds some extra right padding and scrollable space. For the benefit of a simpler, zero-JS approach without runtime DOM manipulation, I think this trade-off is a worthwhile consideration.

@NeatNit

NeatNit commented Sep 27, 2026

Copy link
Copy Markdown

@NeatNit Thanks for the endorsement and for sharing the context behind that decision!

I agree with your observation: with pure CSS, the padding applies across the entire code block, so code blocks with long lines lower down (past Ferris) will receive a right-side buffer when scrolled, regardless of whether it's strictly needed. This is why I labeled my PR as an alternative to your approach, not necessarily a superior one.

With that said, when the Ferris padding is applied, it doesn't harm readability, it simply adds some extra right padding and scrollable space. For the benefit of a simpler, zero-JS approach without runtime DOM manipulation, I think this trade-off is a worthwhile consideration.

Yup, I agree, the trade-offs of my approach aren't worthwhile. But the only trade-offs (to my knowledge) is code complexity and the small layout recalculation after margin is added (which I would expect is very inexpensive in any modern browser). Syntax highlighting and code selection is intact, as can be seen in the screenshots.

DOM manipulation is arguable - yes, I inevitably have to manipulate the DOM to achieve what I wanted, but I don't think there's any downside to this. Everything in ferris.js is DOM manipulation anyway. If I only wanted to add padding (or margin) to specific lines, I had to give them a span.

The setTimeout (which causes a layout recalculation) is unfortunate, but I couldn't find any other way of identifying which lines overlap with Ferris.

Anyway, as I already said, your PR is better because the code complexity simply isn't worth the difference. A little redundant padding doesn't hurt :)

Now let's just hope someone actually checks out this PR ;)

Comment thread ferris.css Outdated

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Symbols can cover up code on smartphones.

2 participants