<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Hao Wu — Build Notes]]></title><description><![CDATA[Practical notes on building useful digital tools: small experiments, tested examples and lessons from shipping. Written by Hao Wu, an independent product maker.]]></description><link>https://wuhao1328675441.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 30 Oct 2026 13:10:50 GMT</lastBuildDate><atom:link href="https://wuhao1328675441.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Your button is 8px too narrow. Stop guessing which CSS value to change.]]></title><description><![CDATA[Reproduce an 8px button mismatch, compare computed CSS values, and fix the padding before changing the layout. Includes a tested example.]]></description><link>https://wuhao1328675441.hashnode.dev/your-button-is-8px-too-narrow-stop-guessing-which-css-value-to-change</link><guid isPermaLink="true">https://wuhao1328675441.hashnode.dev/your-button-is-8px-too-narrow-stop-guessing-which-css-value-to-change</guid><category><![CDATA[CSS]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Hao Wu]]></dc:creator><pubDate>Mon, 26 Oct 2026 02:02:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adc32d03c56f5422d5ba4fa/95de10a2-1064-431a-8d52-b563abe44220.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The color matches. The corners look right. Yet your copied button is still narrower than the reference.</p>
<p>Before adding a fixed width or moving the surrounding layout, compare the values that make up the button. In the example below, the entire mismatch comes from <strong>4px less padding on each side</strong>.</p>
<p>The cover is an original browser-rendered example, not an extension screenshot. Its three states use the same text, font, border and line height. Only horizontal padding changes.</p>
<h2>Reproduce the mismatch</h2>
<p>Paste this into an HTML file:</p>
<pre><code class="language-html">&lt;button class="action reference"&gt;Continue&lt;/button&gt;
&lt;button class="action implementation"&gt;Continue&lt;/button&gt;
&lt;style&gt;
  .action {
    appearance: none;
    box-sizing: border-box;
    display: inline-block;
    margin: 0;
    border: 2px solid #453397;
    border-radius: 12px;
    background: #6d50d9;
    color: white;
    font: 600 18px/24px "Segoe UI", sans-serif;
    padding: 12px 24px;
    white-space: nowrap;
  }
  .implementation { padding-inline: 20px; }
&lt;/style&gt;
</code></pre>
<p>Both buttons size to their content. Their text and borders are identical, but the implementation loses 4px on the left and 4px on the right: <strong>8px in total</strong>.</p>
<p>You can check the rendered widths in DevTools:</p>
<pre><code class="language-js">const reference = document.querySelector('.reference');
const implementation = document.querySelector('.implementation');
console.log(
  reference.getBoundingClientRect().width -
  implementation.getBoundingClientRect().width
); // 8 in this untransformed, unconstrained example
</code></pre>
<p>In our browser check, the widths were 126.21875px and 118.21875px. Changing the implementation's horizontal padding to 24px restored 126.21875px. Absolute widths can vary with the available font; the 8px difference follows from the padding under these conditions.</p>
<p>Adding <code>width: 126.21875px</code> would hide this symptom for this text. It would also bake one label's size into the component. Correct the cause when the padding is supposed to match; choose an explicit width only when your design actually calls for it.</p>
<h2>Before comparing, make the states comparable</h2>
<p>Use the same viewport and corresponding elements. Keep text and interaction state consistent, and wait for fonts to load. A hovered reference and an idle implementation are different states. A different font can change both text width and wrapping.</p>
<p>Compare one group at a time:</p>
<ol>
<li><strong>Typography:</strong> family, size, weight and line height. A declared font family does not prove that the same font file or glyph rendered.</li>
<li><strong>Box model:</strong> padding, borders, margins and box sizing. Inspect the parent layout too; a flex or grid constraint can change the result.</li>
<li><strong>Appearance:</strong> each corner radius, foreground, background and shadow. Check the four corners separately when the shape looks wrong.</li>
</ol>
<p>Computed values describe the current state. They do not identify the winning stylesheet declaration or fully explain inheritance and responsive behavior. Use the DevTools Styles panel to trace those causes.</p>
<h2>Fix one difference, then test the context</h2>
<p>Change the suspected property and compare again. Then check a narrower container and a longer label. The example's arithmetic is useful because it isolates one cause; it is not a general formula for transformed, constrained or wrapping elements.</p>
<p>Some differences are intentional. Your project may use another font or spacing token. The goal is to explain the mismatch and make a deliberate choice, rather than force every number to match a reference.</p>
<h2>An optional cross-page comparison workflow</h2>
<p>I am involved in building Stylegrab. Its free comparison workflow lets you save a reference JSON, load it on your implementation page, select the corresponding element and compare 47 computed style values. It does not automatically read two tabs or upload the whole page. You can investigate the same differences with DevTools.</p>
<p><a href="https://chromewebstore.google.com/detail/bbacodnepolimendegnfedicnmdpanfm">Install the free Chrome extension</a>, or <a href="https://getstylegrab.com/try">try style output on our owned-component sample</a>. The sample does not perform cross-page comparisons. No purchase is required for the comparison workflow.</p>
<p>Try one non-confidential component from work you already do: which difference explained the mismatch, and where did the comparison leave you stuck? Please do not share private pages, reference files or client content.</p>
<p>Disclosure: I am a product maker. Development and this article used AI assistance. The cover's padding example was rendered and its width difference checked in a browser; this is not evidence of user time saved or a guarantee of matching output.</p>
<p>References: <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/padding">MDN padding</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle">MDN getComputedStyle</a>.</p>
]]></content:encoded></item><item><title><![CDATA[24px apart, gap: 0. Where did the space come from?]]></title><description><![CDATA[The same 24px space can come from flex gap or distributed space. Run the example, measure it, then find the layout rule.]]></description><link>https://wuhao1328675441.hashnode.dev/24px-apart-gap-0-where-did-the-space-come-from</link><guid isPermaLink="true">https://wuhao1328675441.hashnode.dev/24px-apart-gap-0-where-did-the-space-come-from</guid><category><![CDATA[CSS]]></category><category><![CDATA[css flexbox]]></category><dc:creator><![CDATA[Hao Wu]]></dc:creator><pubDate>Sun, 25 Oct 2026 15:19:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adc32d03c56f5422d5ba4fa/82a4df4d-5a41-4490-86b9-c37bcfccb509.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Two buttons are 24 pixels apart. Should you change <code>gap</code>, <code>margin</code> or <code>padding</code>?</p>
<p>The number alone cannot tell you. A measurement describes the rendered geometry. A CSS property describes one of the rules that helped produce it. Treating those as the same thing is a common way to fix one layout and break another.</p>
<p>Here is a small example you can use to separate the observation from its cause.</p>
<h2>Start with a layout whose cause you know</h2>
<pre><code class="language-html">&lt;div class="row"&gt;
  &lt;button class="item"&gt;Continue&lt;/button&gt;
  &lt;button class="item"&gt;Details&lt;/button&gt;
&lt;/div&gt;
&lt;style&gt;
  .row { display: flex; gap: 24px; width: 424px; }
  .item {
    box-sizing: border-box;
    flex: 0 0 200px;
    height: 84px;
    margin: 0;
    padding: 16px 24px;
    border: 2px solid #4937ad;
    border-radius: 13px;
    background: #6550df;
    color: white;
    font: 600 24px system-ui, sans-serif;
  }
&lt;/style&gt;
</code></pre>
<p>The two items occupy 400 pixels, and their parent supplies a 24-pixel gap. The items have zero margins. Their padding affects the space inside their border boxes; it is not the 24-pixel space between the boxes.</p>
<p>The comparison image is an original browser rendering of this layout. It illustrates a known cause, rather than pretending that a measurement tool automatically diagnosed it.</p>
<h2>Measure the border boxes</h2>
<pre><code class="language-js">const [a, b] = document.querySelectorAll('.row .item');
const aBox = a.getBoundingClientRect();
const bBox = b.getBoundingClientRect();
console.log(bBox.left - aBox.right); // 24
</code></pre>
<p>This calculation is useful for the simple, untransformed, left-to-right row above. It is not a general distance algorithm for overlapping, wrapped or transformed elements.</p>
<p>Now try this change to the parent:</p>
<pre><code class="language-css">.row {
  gap: 0;
  justify-content: space-between;
}
</code></pre>
<p>The width remains 424 pixels and each item remains 200 pixels wide. The border-to-border distance is still 24 pixels. This time, distributed free space produces the separation, while <code>gap</code> is zero.</p>
<p>That is why “I measured 24 pixels” is an observation, not a diagnosis.</p>
<h2>Inspect the rule before editing</h2>
<p>Select an item and inspect its box model. Check its padding and margins, then select the parent and inspect its layout rules. For flex or grid layouts, check <code>gap</code> as well as alignment and distributed space. Use the browser's layout overlays when they clarify the relationship.</p>
<p>Change one relevant rule, then measure again at the same viewport. If the result moves unexpectedly, check whether the container resized, an item wrapped, or the text changed the item's dimensions. Avoid compensating with an unrelated negative margin before understanding the cause.</p>
<p>The same caution applies to screenshots: visible empty space may include more than one contribution. Vertical block margins can also collapse in layouts where margin collapsing applies; the flex-row example here does not demonstrate that behavior.</p>
<h2>Use a measurement tool as an observation aid</h2>
<p>I am involved in building Stylegrab. In its measurement workflow, pin an element, hold Alt and hover another to inspect their rendered distance. Our <a href="https://www.youtube.com/watch?v=Zz4jeXfOnPw">short, silent demonstration</a> uses an owned sample page. It shows the measurement interaction; it does not automatically identify the layout rule that caused the space.</p>
<p><a class="embed-card" href="https://www.youtube.com/watch?v=Zz4jeXfOnPw">https://www.youtube.com/watch?v=Zz4jeXfOnPw</a></p>

<p>You can do the investigation with DevTools too. If you want to explore example style output first, the <a href="https://getstylegrab.com/try?utm_source=hashnode&amp;utm_medium=community&amp;utm_campaign=spacing-cause">no-install sample</a> runs only on our own components. The Chrome extension includes free inspection and CSS copying; copied values still need checking in your destination layout.</p>
<p>What usually causes the most confusion in your own layouts: item margins, parent gap, distributed space or wrapping? Please use non-confidential examples.</p>
<p>Disclosure: product development and this article used AI assistance. The fixed-width flex example was checked in a browser, including the same distance with gap and with space-between.</p>
<p>Technical reference: <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/gap">MDN gap</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Why a copied button loses its text color — and how to check it]]></title><description><![CDATA[Reproduce an inherited-color change, inspect computed styles, and adapt a copied button with a small HTML and CSS example.]]></description><link>https://wuhao1328675441.hashnode.dev/why-a-copied-button-loses-its-text-color-and-how-to-check-it</link><guid isPermaLink="true">https://wuhao1328675441.hashnode.dev/why-a-copied-button-loses-its-text-color-and-how-to-check-it</guid><category><![CDATA[CSS]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Hao Wu]]></dc:creator><pubDate>Sat, 24 Oct 2026 04:30:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adc32d03c56f5422d5ba4fa/768ede76-2f09-44d8-aded-210f41c54d5b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A button can look correct on its original page and change color when moved into another project. Before adding more declarations, check whether the color actually belongs to the button or comes from its parent.</p>
<h2>Reproduce the difference</h2>
<p>Here is a small example you can run on your own page:</p>
<pre><code class="language-html">&lt;div class="reference"&gt;&lt;button class="action"&gt;Continue&lt;/button&gt;&lt;/div&gt;
&lt;div class="destination"&gt;&lt;/div&gt;
&lt;style&gt;
.reference { color: #5533aa; }
.action {
  font: inherit;
  color: inherit;
  padding: 12px 20px;
  border: 1px solid currentColor;
  border-radius: 14px;
  background: white;
}
.destination { color: #172033; }
&lt;/style&gt;
</code></pre>
<p>The button explicitly inherits its color. Copying the same class into a container with a different color changes the rendered result. Copying only the declarations is therefore different from carrying over the original rendered appearance.</p>
<p><img src="https://getstylegrab.com/img/inheritance-comparison.png" alt="The same button inherits purple text in the reference container and dark text in the destination." /></p>
<p><em>Actual browser rendering: the right button is cloned from the left. Only the parent color changes.</em></p>
<h2>Inspect the result, then trace its source</h2>
<p>In DevTools, select the button and compare the Styles and Computed panels. Styles helps explain where a rule comes from. Computed helps you check the result that the browser resolved in the current page. Neither view reconstructs the entire component for you.</p>
<p>On a page you own, you can inspect the values directly:</p>
<pre><code class="language-js">const button = document.querySelector('.reference .action');
const styles = getComputedStyle(button);
console.table({ color: styles.color, font: styles.fontFamily,
  padding: styles.padding, radius: styles.borderTopLeftRadius });
</code></pre>
<p>To reproduce the move without changing the original:</p>
<pre><code class="language-js">const copy = button.cloneNode(true);
document.querySelector('.destination').append(copy);
console.log(getComputedStyle(copy).color);
</code></pre>
<p>In this example the original resolves to <code>rgb(85, 51, 170)</code> and the destination resolves to <code>rgb(23, 32, 51)</code>. The button class is the same; its inherited context changed.</p>
<h2>Adapt the component in its destination</h2>
<p>If preserving the appearance matters, set the intended color in the destination's own component styles, or map it to your project's token. Do not copy the reference token name unless that token also exists in the destination. Repeat the check for fonts: naming a font family does not load the font file.</p>
<p>Keep the viewport and state consistent while comparing. A snapshot of a button at one width does not establish its hover, focus, disabled or responsive behavior. Check those separately before treating it as a finished component.</p>
<h2>A small workflow to try</h2>
<p>Inspect one component, identify inherited values, copy only what the destination needs, then test it in that layout. You can do this with DevTools. I am also involved in building Stylegrab for quicker inspection and CSS copying; <a href="https://getstylegrab.com/try?utm_source=hashnode&amp;utm_medium=community&amp;utm_campaign=inherited-color">our owned-component sample</a> can be tried without installation. The sample does not inspect other websites. The Chrome extension has free inspection tools; exports remain starting points that need adaptation.</p>
<p>Which inherited value most often surprises you after copying a component? Please use your own examples and avoid sharing private or client pages.</p>
<p><strong>Disclosure:</strong> product development and this article used AI assistance. The inherited-color example was checked in a browser.</p>
<p><strong>Technical reference:</strong> <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle">MDN: Window.getComputedStyle()</a>.</p>
]]></content:encoded></item></channel></rss>