Skip to content

Commit

Permalink
Add note about right padding when child overflows
Browse files Browse the repository at this point in the history
- Add support for diff notation in code blocks
- Allow long inline links in articles to break
- Add Inter 700 font for strong elements
- Other minor fixes, tweaks, and refactorings
  • Loading branch information
mcecode committed Jul 17, 2024
1 parent 460f54c commit e6ca0f3
Show file tree
Hide file tree
Showing 11 changed files with 308 additions and 55 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ My personal website, built with [Astro](https://astro.build) and deployed on [Gi

## Third-party assets and attributions

- [Inter](https://rsms.me/inter) ([1](public/fonts/inter-v13-latin-400.woff2)) is licensed under the [SIL Open Font License (OFL)](https://github.com/rsms/inter/blob/master/LICENSE.txt).
- [Inter](https://rsms.me/inter) ([1](public/fonts/inter-v13-latin-400.woff2), [2](public/fonts/inter-v13-latin-700.woff2)) is licensed under the [SIL Open Font License (OFL)](https://github.com/rsms/inter/blob/master/LICENSE.txt).
- [Raleway](https://github.com/impallari/Raleway) ([1](public/fonts/raleway-v29-latin-500.woff2), [2](public/fonts/raleway-v29-latin-600.woff2)) is licensed under the [SIL Open Font License (OFL)](https://github.com/impallari/Raleway/blob/master/OFL.txt).
- [Kode Mono](https://kodemono.com) ([1](public/fonts/kode-mono-v2-latin-400.woff2)) is licensed under the [SIL Open Font License (OFL)](https://github.com/isaozler/kode-mono/blob/main/OFL.txt).
- [`avatar.png`](src/assets/avatar.png) was created by [Marga Hernandez](https://margahernandez.framer.website).
Expand Down
60 changes: 53 additions & 7 deletions astro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { RehypePlugin } from "@astrojs/markdown-remark";
import type { AstroIntegration, AstroUserConfig } from "astro";
import type { Options as AutolinkHeadingsOptions } from "rehype-autolink-headings";
import type { Options as ClassNamesOptions } from "rehype-class-names";
import type { Options as ExternalLinksOptions } from "rehype-external-links";
import type {
LegacyAsyncImporter,
LegacySharedOptions,
Expand All @@ -21,13 +22,15 @@ import mdx from "@astrojs/mdx";
// @ts-expect-error - There's no type declaration but it exists.
import remarkA11yEmoji from "@fec/remark-a11y-emoji";
import { addExtension, createFilter, dataToEsm } from "@rollup/pluginutils";
import { transformerNotationDiff } from "@shikijs/transformers";
import compress from "astro-compress";
import { walk } from "estree-walker";
import findCacheDirectory from "find-cache-dir";
import gifsicle from "gifsicle";
import { customAlphabet } from "nanoid";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import rehypeClassNames from "rehype-class-names";
import rehypeExternalLinks from "rehype-external-links";
import sharp from "sharp";
sharp.cache(false);

Expand All @@ -37,6 +40,9 @@ sharp.cache(false);

const classNamesTransformer: ShikiTransformer = {
name: "class-names",
pre(node) {
node.properties.class = "block-code-wrapper";
},
code(node) {
node.properties.class = "block-code";
},
Expand All @@ -51,12 +57,12 @@ const classNamesPlugin: [RehypePlugin, ClassNamesOptions] = [
rehypeClassNames,
{ ":not(pre) > code": "inline-code" }
];
const diffNotationTransformer = transformerNotationDiff({
classActivePre: "",
classLineAdd: "diff insert",
classLineRemove: "diff delete"
});

// Workaround since 'shikiConfig' does not support 'defaultColor' and
// 'cssVariablePrefix' options yet. This manually does what happens when
// 'defaultColor' is set to 'false' and 'cssVariablePrefix' is set to
// '--c-code-'.
// https://github.com/withastro/astro/issues/11238#issuecomment-2165715631
function replaceShikiProperty(
style: string,
property: "background-color" | "--shiki-dark-bg" | "color" | "--shiki-dark"
Expand Down Expand Up @@ -87,6 +93,15 @@ function replaceShikiProperty(

return style.replace(regex, `${variableName}:${hex}`);
}
/**
* Workaround since 'shikiConfig' does not support 'defaultColor' and
* 'cssVariablePrefix' options yet. This manually does what happens when
* 'defaultColor' is set to 'false' and 'cssVariablePrefix' is set to
* '--c-code-'.
*
* @see
* {@link https://github.com/withastro/astro/issues/11238#issuecomment-2165715631}
*/
const themeTransformer: ShikiTransformer = {
name: "theme",
pre(node) {
Expand Down Expand Up @@ -114,6 +129,28 @@ const autolinkHeadingsPlugin: [RehypePlugin, AutolinkHeadingsOptions] = [
{ behavior: "wrap" }
];

/**
* Hijacks rehype-external-links to add classes to links whose href value
* matches its text content instead of adding rel and target attributes.
*/
const externalLinksPlugin: [RehypePlugin, ExternalLinksOptions] = [
rehypeExternalLinks,
{
rel: [],
test: (element) => {
if (
element.children[0]?.type === "text" &&
element.properties.href === element.children[0].value
) {
return true;
}

return false;
},
properties: { class: "word-break-all" }
}
];

//==================================================
// Astro - Integrations
//==================================================
Expand Down Expand Up @@ -410,10 +447,19 @@ export default <AstroUserConfig>{
smartypants: false,
shikiConfig: {
themes: { light: "slack-ochin", dark: "slack-dark" },
transformers: [classNamesTransformer, themeTransformer]
transformers: [
classNamesTransformer,
diffNotationTransformer,
themeTransformer
]
},
remarkPlugins: [remarkA11yEmoji],
rehypePlugins: [classNamesPlugin, rehypeHeadingIds, autolinkHeadingsPlugin]
rehypePlugins: [
classNamesPlugin,
rehypeHeadingIds,
autolinkHeadingsPlugin,
externalLinksPlugin
]
},
integrations: [mdx(), optimizeImagesIntegration, compress({ Image: false })],
vite: { css: { preprocessorOptions: { scss } }, plugins: [generateIdsPlugin] }
Expand Down
58 changes: 51 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"@astrojs/mdx": "^3.1.1",
"@fec/remark-a11y-emoji": "^4.0.2",
"@rollup/pluginutils": "^5.0.2",
"@shikijs/transformers": "^1.10.1",
"@types/gifsicle": "^5.2.0",
"@types/node": "^20.2.3",
"astro": "^4.5.6",
Expand All @@ -19,6 +20,7 @@
"nanoid": "^5.0.6",
"rehype-autolink-headings": "^7.1.0",
"rehype-class-names": "^2.0.0",
"rehype-external-links": "^3.0.0",
"sass": "^1.62.1",
"sharp": "^0.33.2"
}
Expand Down
Binary file added public/fonts/inter-v13-latin-700.woff2
Binary file not shown.
7 changes: 7 additions & 0 deletions src/components/page/fonts.astro
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
font-display: swap;
src: url("/fonts/inter-v13-latin-400.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/inter-v13-latin-700.woff2") format("woff2");
}
@font-face {
font-family: "Raleway";
font-style: normal;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
title: "What Do: Right Padding Doesn’t Apply to Overflowing Child"
dateCreated: 2024-07-17
dateUpdated: 2024-07-17
---

Given this HTML:

```html
<div id="parent">
<div id="child">Some overflowing content...</div>
</div>
```

And this CSS:

```css
#parent {
height: 200px;
width: 200px;
padding: 20px;
background: green;
overflow-x: auto;
}
#child {
width: 500px;
background: greenyellow;
}
```

You'd think that there would be 20 pixels of space on all sides between `#parent` and `#child` from the set padding. For some browsers and contexts that's correct, but for others, there won't be 20 pixels of space on the right side when you scroll to show the end of `#child`.

What do if you want that right spacing for all browsers and contexts?

Instead of putting padding on `#parent`, put margin on `#child`:

```css
#parent {
height: 200px;
width: 200px;
padding: 20px; // [!code --]
background: green;
overflow-x: auto;
}
#child {
display: inline-block; // [!code ++]
width: 500px;
margin: 20px; // [!code ++]
background: greenyellow;
}
```

**Note:** Setting `display` to `inline-block` on `#child` is important for the spacing to apply properly.

## Additional Information

I played around with different browsers and situations to test when the right spacing does and does not get applied when setting padding on `#parent`. I used Brave on Linux to represent Blink-based browsers, Safari on iOS to represent WebKit-based browsers, and Firefox on Linux to represent Gecko-based browsers because those are what I have available.

From this, I found that the right spacing is always applied on Blink-based browsers (e.g., Chrome, Edge). For WebKit-based browsers, it only gets applied if `#parent` is a `pre` element and `#child` is one of `code`, `samp`, or `kbd`. Lastly, when it comes to Gecko-based browsers, the right spacing never gets applied.

Why is there such a stark difference in the behavior of these browsers and engines?

Well, perusing through the CSS 2.1 spec as well as some Working Drafts, and by perusing of course, I mean just Ctrl+F-ing my way through them, I couldn't find a specific answer as to how to handle the situation that I've outlined so far. Maybe I just missed or misconstrued something since I don't usually read specs, but the closest thing I found to an answer is the start of the description of how `overflow: scroll` should work:

> This value indicates that the content is clipped to the padding box, but can be scrolled into view (and therefore the box is a scroll container).
And this part about how overflow scrolling should work:

> CSS also allows a box to be scroll container that allows the user to scroll clipped parts of its scrollable overflow area into view. The visual viewport of a scroll container (through which the scrollable overflow area can be viewed) coincides with its padding box, and is called the scrollport.
The way I understand it is that when a child overflows its parent and the parent is allowed to scroll to show the rest of the child, the space that's allotted for viewing that content is until the parent's padding. Notice, however, that no instruction is given on whether the right padding should be visible to the user if the end of a horizontally overflowing child is shown through scrolling. This probably left vendors to decide for themselves on how to handle that situation. Hence, the difference in behavior from browser to browser.

I must note though that there is also no instruction as to what to do with a parent's bottom padding when a child is vertically overflowing. However, this problem doesn't arise there. The parent's bottom padding is always visible across the browsers I tested when showing the end of a vertically overflowing child by scrolling the parent.

Another thing to note is that the right padding is always visible when the parent's `display` is `grid` or when it's set to `flex` and its main axis is set vertically with `flex-direction` having either `column` or `column-reverse` as its value. This might be due to the changes to the inner display type these `display` values set. It may also be connected to this clause under what constitutes a scrollable overflow area:

> Additional padding added to the end-side of the scrollable overflow rectangle as necessary to enable a scroll position that satisfies the requirements of place-content: end alignment.
And this note about padding when a grid container is also a scroll container:

> Beware the interaction with padding when the grid container is a scroll container: additional padding is defined to be added to the scrollable overflow rectangle as needed to enable place-content: end alignment of scrollable content.
## Thoughts

Browser interoperability has come a long way from the Internet Explorer days, but it's interesting to see these little peculiarities where browsers still differ in behavior. Maybe it's because this problem has existed for a long time before even Flexbox and Grid were a thing, that they just end up not being addressed (or maybe because it's not really worth caring about).

It would certainly be interesting to look at browser code to see if there's a reason why they implemented things the way they did, but I neither have the time nor the C++ knowledge to do that. So I'll leave it as is with my half-baked "research".

Why did I do this? What's the use of this? Is it worth thinking about all this just for some spacing? Well, not really. Even if you don't use the workaround stated, you'll still be fine. Chromium-based browsers have around 70% market share, so the problem doesn't exist for all of those people. If you're just showing some code with `pre` and `code` elements like me, there's also no problem for the Safari people either, bringing your support to like 90%. As for the rest, how many will even care for that right spacing 🤷‍♂️? Nonetheless, I enjoy exploring these little browser quirks from time to time and implementing workarounds for them in my sites when I remember them.

## References

- <https://stackoverflow.com/a/10055302>
- <https://www.brunildo.org/test/overscrollback.html>
- <https://www.w3.org/TR/2011/REC-CSS2-20110607/visufx.html>
- <https://www.w3.org/TR/CSS22/visufx.html>
- <https://www.w3.org/TR/css-overflow-3>
- <https://www.w3.org/TR/css-box-3>
- <https://www.w3.org/TR/css-grid-1>
Loading

0 comments on commit e6ca0f3

Please sign in to comment.