From e6ca0f3bfaf9c841d0d3d820a83228156ad07a84 Mon Sep 17 00:00:00 2001 From: Matthew Espino <65783406+mcecode@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:12:41 +0800 Subject: [PATCH] Add note about right padding when child overflows - 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 --- README.md | 2 +- astro.config.ts | 60 ++++++++- package-lock.json | 58 ++++++++- package.json | 2 + public/fonts/inter-v13-latin-700.woff2 | Bin 0 -> 22904 bytes src/components/page/fonts.astro | 7 + ...dding-doesnt-apply-to-overflowing-child.md | 99 ++++++++++++++ src/styles/article.scss | 122 ++++++++++++------ src/styles/data/colors.json | 4 +- src/styles/page.scss | 6 + src/styles/partials/_variables.scss | 3 +- 11 files changed, 308 insertions(+), 55 deletions(-) create mode 100644 public/fonts/inter-v13-latin-700.woff2 create mode 100644 src/content/notes/what-do-right-padding-doesnt-apply-to-overflowing-child.md diff --git a/README.md b/README.md index 980c150..e741815 100644 --- a/README.md +++ b/README.md @@ -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). diff --git a/astro.config.ts b/astro.config.ts index 9765bcc..2bc1584 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -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, @@ -21,6 +22,7 @@ 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"; @@ -28,6 +30,7 @@ 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); @@ -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"; }, @@ -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" @@ -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) { @@ -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 //================================================== @@ -410,10 +447,19 @@ export default { 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] } diff --git a/package-lock.json b/package-lock.json index 28a7120..f8be3fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,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", @@ -18,6 +19,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" } @@ -1912,12 +1914,22 @@ ] }, "node_modules/@shikijs/core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.9.1.tgz", - "integrity": "sha512-EmUful2MQtY8KgCF1OkBtOuMcvaZEvmdubhW0UHCGXi21O9dRLeADVCj+k6ZS+de7Mz9d2qixOXJ+GLhcK3pXg==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.10.1.tgz", + "integrity": "sha512-qdiJS5a/QGCff7VUFIqd0hDdWly9rDp8lhVmXVrS11aazX8LOTRLHAXkkEeONNsS43EcCd7gax9LLoOz4vlFQA==", "dev": true, "license": "MIT" }, + "node_modules/@shikijs/transformers": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.10.1.tgz", + "integrity": "sha512-0gLtcFyi6R6zcUkFajUEp1Qiv7lHBSFgOz4tQvS8nFsYCQSLI1/9pM+Me8jEIPXv7XLKAoUjw6InL+Sv+BHw/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "shiki": "1.10.1" + } + }, "node_modules/@sindresorhus/is": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", @@ -5702,6 +5714,19 @@ "node": ">=4" } }, + "node_modules/is-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-alphabetical": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", @@ -8659,6 +8684,25 @@ "unified": "^11.0.4" } }, + "node_modules/rehype-external-links": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", + "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-is-element": "^3.0.0", + "is-absolute-url": "^4.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-parse": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.0.tgz", @@ -9209,13 +9253,13 @@ } }, "node_modules/shiki": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.9.1.tgz", - "integrity": "sha512-8PDkgb5ja3nfujTjvC4VytL6wGOGCtFAClUb2r3QROevYXxcq+/shVJK5s6gy0HZnjaJgFxd6BpPqpRfqne5rA==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.10.1.tgz", + "integrity": "sha512-uafV7WCgN4YYrccH6yxpnps6k38sSTlFRrwc4jycWmhWxJIm9dPrk+XkY1hZ2t0I7jmacMNb15Lf2fspa/Y3lg==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/core": "1.9.1" + "@shikijs/core": "1.10.1" } }, "node_modules/signal-exit": { diff --git a/package.json b/package.json index d34916d..803726d 100644 --- a/package.json +++ b/package.json @@ -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", @@ -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" } diff --git a/public/fonts/inter-v13-latin-700.woff2 b/public/fonts/inter-v13-latin-700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..775f7575e653614760dba82fd9dffaddb939770f GIT binary patch literal 22904 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

p9mvRq3FeHt~X*bZJ9} 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 J`~QD_kKOs6|ET}~ literal 0 HcmV?d00001 diff --git a/src/components/page/fonts.astro b/src/components/page/fonts.astro index f600246..dfbd6c2 100644 --- a/src/components/page/fonts.astro +++ b/src/components/page/fonts.astro @@ -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; diff --git a/src/content/notes/what-do-right-padding-doesnt-apply-to-overflowing-child.md b/src/content/notes/what-do-right-padding-doesnt-apply-to-overflowing-child.md new file mode 100644 index 0000000..0a0c580 --- /dev/null +++ b/src/content/notes/what-do-right-padding-doesnt-apply-to-overflowing-child.md @@ -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 +

+
Some overflowing content...
+
+``` + +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 + +- +- +- +- +- +- +- diff --git a/src/styles/article.scss b/src/styles/article.scss index a7149ed..f84f0e0 100644 --- a/src/styles/article.scss +++ b/src/styles/article.scss @@ -1,3 +1,32 @@ +article { + padding-bottom: v-const("section_spacing.small"); + + p, + ul, + pre, + a:has(picture) { + margin-bottom: v-size(6, "em"); + } + + li { + list-style: circle inside; + } + + a:has(picture), + picture { + display: inline-block; + } + img { + vertical-align: middle; + } + + blockquote { + padding-left: v-size(4, "em"); + border-left: 2px solid var(--c-accent-1); + color: var(--c-accent-1); + } +} + // Inspired from MDN's heading link styles h2 a { text-decoration: none; @@ -23,53 +52,70 @@ h2 a { } } -article { - padding-bottom: v-size(10); +// Inspired from GitHub's inline code styles +.inline-code { + padding: v-size(1, "em") v-size(2, "em"); + border-radius: 6px; + background-color: var(--c-accent-2); +} - p, - ul, - pre, - a:has(picture) { - margin-bottom: v-size(6, "em"); - } +$codeSpacing: v-size(6, "em"); +.block-code-wrapper { + border-radius: 10px; + background-color: var(--c-code-light-bg); + color: var(--c-code-light); - li { - list-style: circle inside; + @include m-dark { + background-color: var(--c-code-dark-bg); + color: var(--c-code-dark); } +} +.block-code { + display: inline-block; + min-width: calc(100% - $codeSpacing * 2); + margin: $codeSpacing; +} +.block-code-line.diff { + position: relative; + display: inline-block; + width: 100%; - // Inspired from GitHub's inline code styles - .inline-code { - padding: 0.2em 0.4em; - border-radius: 6px; - background-color: var(--c-accent-2); + &::before { + position: absolute; + left: -#{v-size(4, "em")}; } - pre { - border-radius: 10px; - background-color: var(--c-code-light-bg); - color: var(--c-code-light); - @include m-dark { - background-color: var(--c-code-dark-bg); - color: var(--c-code-dark); - } + &::after { + content: ""; + position: absolute; + left: -#{$codeSpacing}; + min-height: 100%; + width: calc(100% + $codeSpacing * 2); + opacity: 15%; } - .block-code { - display: inline-block; - margin: v-size(4, "em") v-size(6, "em"); +} +.block-code-line.insert { + &::before { + content: "+"; } - .block-code-token { - color: var(--c-code-light); - - @include m-dark { - color: var(--c-code-dark); - } + &::after { + background-color: v-color("green"); } - - a:has(picture), - picture { - display: inline-block; +} +.block-code-line.delete { + &::before { + content: "-"; } - img { - vertical-align: middle; + &::after { + background-color: v-color("red"); + } +} +.block-code-token { + position: relative; + z-index: 1; + color: var(--c-code-light); + + @include m-dark { + color: var(--c-code-dark); } } diff --git a/src/styles/data/colors.json b/src/styles/data/colors.json index c287abf..03bf57d 100644 --- a/src/styles/data/colors.json +++ b/src/styles/data/colors.json @@ -3,6 +3,8 @@ "white": "#f9f9f9", "black": "#0a0a0a", "grayLight": "#bcbcbc", - "grayDark": "#3c3c3c" + "grayDark": "#3c3c3c", + "green": "#3dd68c", + "red": "#f43f5e" } } diff --git a/src/styles/page.scss b/src/styles/page.scss index affbbab..6d45408 100644 --- a/src/styles/page.scss +++ b/src/styles/page.scss @@ -66,6 +66,9 @@ a { text-decoration-style: dotted; } } +strong { + font-weight: 700; +} button { cursor: pointer; } @@ -133,6 +136,9 @@ code { font-size: v-size(3); color: var(--c-accent-1); } +.word-break-all { + word-break: break-all; +} h1.larger-spacing { margin-bottom: v-size(5, "em"); } diff --git a/src/styles/partials/_variables.scss b/src/styles/partials/_variables.scss index a3c7e60..a17aa57 100644 --- a/src/styles/partials/_variables.scss +++ b/src/styles/partials/_variables.scss @@ -1,4 +1,5 @@ @use "sass:list"; +@use "sass:string"; @use "lib"; @@ -7,7 +8,7 @@ @use "json:colors" as *; @function color($color) { - @return lib.deep-get($colors, $color); + @return string.unquote(lib.deep-get($colors, $color)); } // Fonts