Skip to content

Commit e161525

Browse files
committed
Prevent code badges from scrolling along with code
The `::before` trick we've been using to add badges has never interacted well with the `overflow-x: auto` we set on the parent `<pre>`: `position: absolute` positions relative to the unscrolled container and doesn't "stick" when the container is scrolled, resulting in the badge leaving the right edge of the block when wide code is scrolled. Until now, that issue has been masked by the fact that highlight.js gives the `<code>` its own `overflow-x: auto`. Since we've stopped using highlight.js, we need to fix the issue properly. The root cause is described well in this article[1]. As it demonstrates, all solutions not involving an extra wrapper div take a lot of code and are pretty hacky. In addition, the last example--closest to our case-- requires the badge itself to have nested divs, which can't be done with `::before`. As such, just use JS to add a wrapper div, which actually simplifies both the CSS and the JS significantly. [1] https://www.horuskol.net/blog/2022-04-13/relative-and-absolute-scrolling-blues/
1 parent 3044ece commit e161525

File tree

2 files changed

+46
-54
lines changed

2 files changed

+46
-54
lines changed

_includes/extensions/code-highlight.html

Lines changed: 45 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,67 +19,66 @@
1919
{%- if badge_enabled -%}
2020
<script>
2121
document.addEventListener('DOMContentLoaded', function(event) {
22-
var els = document.querySelectorAll('pre code')
23-
24-
function addLangData(block) {
25-
var outer = block.parentElement.parentElement.parentElement;
26-
var lang = block.getAttribute('data-lang');
27-
for (var i = 0; i < outer.classList.length; i++) {
28-
var cls = outer.classList[i];
22+
function getLangFromClass(elem) {
23+
for (cls of elem.classList) {
2924
if (cls.startsWith('language-')) {
30-
lang = cls;
31-
break;
25+
return cls.substr(9);
3226
}
3327
}
34-
if (!lang) {
35-
cls = block.getAttribute('class');
36-
lang = cls ? cls : '';
37-
}
38-
if (lang.startsWith('language-')) {
39-
lang = lang.substr(9);
40-
}
41-
block.parentNode.setAttribute('data-lang', lang);
28+
return null;
4229
}
4330

44-
function addBadge(block) {
45-
var enabled = ('{{ badge_enabled }}' || 'true').toLowerCase();
46-
if (enabled == 'true') {
47-
var pre = block.parentElement;
48-
pre.classList.add('badge');
49-
}
50-
}
31+
function addBadge(preElem, lang) {
32+
let badgeWrapper = document.createElement('div');
33+
badgeWrapper.classList.add('badge-wrapper')
5134

52-
function handle(block) {
53-
addLangData(block);
54-
addBadge(block)
55-
}
35+
let badge = document.createElement('div');
36+
badge.classList.add('badge');
37+
badge.append(lang);
5638

57-
for (var i = 0; i < els.length; i++) {
58-
var el = els[i];
59-
handle(el);
39+
preElem.replaceWith(badgeWrapper);
40+
badgeWrapper.append(badge, preElem);
6041
}
42+
43+
// Kramdown code blocks
44+
document.querySelectorAll('.highlighter-rouge').forEach((e) => {
45+
let pre = e.querySelector('pre');
46+
if (pre !== null) {
47+
let lang = getLangFromClass(e);
48+
if (lang !== null) {
49+
addBadge(pre, lang);
50+
}
51+
}
52+
});
53+
54+
// Liquid code blocks
55+
document.querySelectorAll('pre > code').forEach((e) => {
56+
let lang = e.getAttribute('data-lang');
57+
if (lang !== null) {
58+
addBadge(e.parentElement, lang);
59+
}
60+
});
6161
});
6262
</script>
6363

6464
<style>
65-
/* code language badge */
66-
pre.badge::before {
67-
content: attr(data-lang);
68-
color: {{badge_color}};
69-
background-color: {{badge_background_color}};
70-
padding: 0 .5em;
71-
border-radius: 0 2px;
72-
text-transform: {{badge_text_transform}};
73-
text-align: center;
74-
min-width: 32px;
75-
display: inline-block;
65+
.badge-wrapper {
66+
position: relative;
67+
}
68+
69+
.badge-wrapper .badge {
7670
position: absolute;
71+
top: 0;
7772
right: 0;
78-
}
7973

80-
/* fix wrong badge display for firefox browser */
81-
code > table pre::before {
82-
display: none;
74+
min-width: 32px;
75+
padding: 0 .5em;
76+
border-bottom-left-radius: 2px;
77+
text-align: center;
78+
79+
color: {{badge_color}};
80+
background-color: {{badge_background_color}};
81+
text-transform: {{badge_text_transform}};
8382
}
8483
</style>
8584
{%- endif -%}

_sass/yat/_base.scss

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,8 @@ code {
157157

158158
pre {
159159
overflow-x: auto;
160-
position: relative;
161160
background-color: #f0f0f0;
162-
163-
> code {
164-
display: inline-block;
165-
padding: 20px!important;
166-
background-color: transparent;
167-
border: 0;
168-
}
161+
padding: 20px;
169162

170163
table, pre {
171164
margin-bottom: 0;

0 commit comments

Comments
 (0)