The anchor link with an anchor icon (fa-anchor) that was permanently displayed at the end of the headings (h2 and so on) on this blog had started to feel a bit uncool to me.
Referring to the heading design of Qiita
(in Japanese), I decided to rethink how it is displayed, including the effect on SEO. While I was at it, I also adjusted the line height and margins of the body text to match the article style of note
(in Japanese).
This is a record of the work, in which I left almost all of the code changes to generative AI instead of doing them by hand, and checked the local appearance with Playwright MCP as I went.
Adjusting the body line height and margins
Referring to the articles published on note.com, I reviewed .blog-post p / .blog-post li in static/css/custom.css.
Comparison with the reference articles
Using Playwright MCP, I measured getComputedStyle directly on both my own site and note.com, and compared the numbers.
| Item | note.com (PC) | After the change (PC) | note.com (390px) | After the change (767px and below) |
|---|---|---|---|---|
| Font size | 18px | 18px (unchanged) | 16px | 16px |
| line-height | 36px (2.0x) | 36px | 32px (2.0x) | 32px |
| Paragraph margin | 36px top and bottom | margin: 0 0 36px | 30px top and bottom | margin: 0 0 30px |
What I changed
- Changed
line-heightfrom1.8to2 - Added
margin: 0 0 36pxto paragraphs - Added a media query that shrinks to
font-size: 16px/line-height: 2/margin: 0 0 30pxat the 767px-and-below breakpoint
What I did not change
I left the left and right margins (padding) alone, because measurement showed note.com at 16px against my current 15px, which is almost the same.
Verification
With hugo server -D (localhost:1313) I checked both PC width and mobile width (390px) through Playwright MCP, and after the styles took effect I confirmed the appearance with screenshots. The temporary files used for verification (.playwright-mcp/ and the screenshot PNGs) were deleted once the work was done.
Changing the heading anchor links to a Qiita style
I inspected Qiita’s article pages directly in the browser (using getComputedStyle and forcePseudoState over CDP) and confirmed that the following implementation is the basis.
- The icon is
fa-link(a chain). It is placed outside the heading on the left withposition: absolute; left: -33px; - Normally
display: none, and shown withflexonly while the heading is hovered
With that in mind, I made the following changes.
layouts/_default/single.html
- {{ .Content | replaceRE "(<h[1-9] id=\"([^\"]+)\".+)(</h[1-9]+>)" "${1} <a class=\"headline-hash\" href=\"#${2}\"><i class=\"fas fa-anchor\"></i></a> ${3}" | safeHTML}}
+ {{ .Content | replaceRE "(<h[1-9] id=\"([^\"]+)\".+)(</h[1-9]+>)" "${1}<a class=\"headline-hash\" href=\"#${2}\" aria-label=\"見出しへのリンク\"><i class=\"fas fa-link\" aria-hidden=\"true\"></i></a>${3}" | safeHTML}}
- Changed the icon from
fa-anchortofa-link - Added
aria-labelto improve screen reader support - Removed
because the positioning switches to absolute
static/css/custom.css
.blog-post h1,
.blog-post h2,
.blog-post h3,
.blog-post h4:not(.see-also),
.blog-post h5,
.blog-post h6 {
position: relative;
}
.blog-post h1,
.blog-post h2 {
margin-top: 2.4em;
padding-bottom: 0.25em;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}
.headline-hash {
position: absolute;
top: 0;
left: -1.3em;
display: flex;
align-items: center;
justify-content: center;
width: 1.3em;
height: 100%;
color: rgba(0, 0, 0, 0.6);
text-decoration: none;
opacity: 0;
transition: opacity 0.15s ease, color 0.15s ease;
}
.headline-hash .fa-link {
font-size: 0.6em;
}
.headline-hash:hover {
color: #0366d6;
}
.blog-post h1:hover .headline-hash,
.blog-post h2:hover .headline-hash,
.blog-post h3:hover .headline-hash,
.blog-post h4:hover .headline-hash,
.blog-post h5:hover .headline-hash,
.blog-post h6:hover .headline-hash,
.headline-hash:focus {
opacity: 1;
}
/* Below 992px there is no offset column and therefore no room to place the icon to the left of the heading, so fall back to showing it at the end */
@media only screen and (max-width: 991px) {
.headline-hash {
position: static;
display: inline-flex;
width: auto;
height: auto;
margin-left: 0.4em;
opacity: 0.4;
}
}I added an underline to h1 and h2 to make the section breaks clearer.
Qiita switches between display: none and flex, which makes the element impossible to reach with keyboard focus, so I did not follow that part and changed it to opacity control instead, making it visible on :focus as well.
In the Bootstrap grid, the left offset on the article body column (col-md-offset-1 / col-lg-offset-2) is only applied at 992px and above, so below 992px I dropped the absolute positioning and prepared a fallback in @media (max-width: 991px) that always shows the icon inline and faintly at the end of the heading.
Verification
- Checked the rendering with a local
hugo server -D - Forced the hover state with CDP’s
forcePseudoStateand confirmed with a screenshot that the chain icon appears to the left of the heading at desktop width (1280px) - Confirmed the same hover behavior with Playwright MCP as well
- Confirmed the fallback where the icon is always shown faintly at the end at mobile width (390px)
- Confirmed with
ReadLintsthat there are no syntax errors in the CSS or the template
Summary
I replaced the heading anchor’s fa-anchor with fa-link and changed it to a Qiita-style design that appears only on hover, and along with that matched the body line height and paragraph margins to note.com’s style based on actual measurements.
Absolute positioning to the left of the heading only holds up in layouts of 992px and above, so on narrow screens I prepared a fallback that displays the icon at the end of the heading to avoid breaking the layout.
I had been thinking myself that the line spacing was a little tight, so maybe it has become a bit easier to read?