<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Benjamin Olsen</title>
    <description>The latest articles on DEV Community by Benjamin Olsen (@benjaminolsen).</description>
    <link>https://dev.to/benjaminolsen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4190216%2Ff00be6fd-0cc7-4703-a21a-9b4048de6853.png</url>
      <title>DEV Community: Benjamin Olsen</title>
      <link>https://dev.to/benjaminolsen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/benjaminolsen"/>
    <language>en</language>
    <item>
      <title>Turn an Oxygen service-site starter into four connected pages</title>
      <dc:creator>Benjamin Olsen</dc:creator>
      <pubDate>Sat, 17 Oct 2026 10:47:33 +0000</pubDate>
      <link>https://dev.to/benjaminolsen/turn-an-oxygen-service-site-starter-into-four-connected-pages-8d9</link>
      <guid>https://dev.to/benjaminolsen/turn-an-oxygen-service-site-starter-into-four-connected-pages-8d9</guid>
      <description>&lt;p&gt;A starter layout can give you a useful visual structure while still leaving important website work undone.&lt;/p&gt;

&lt;p&gt;For a small service business, I would begin with Home, Services, About and Contact. A visitor should understand the offer, inspect who is behind it and find a working way to enquire.&lt;/p&gt;

&lt;p&gt;Here is the adaptation workflow for the free Oxygen service-site kit I maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use an empty staging site first
&lt;/h2&gt;

&lt;p&gt;Back up the destination before importing. The kit uses a native Design Set with shared selectors. In the Oxygen versions previously tested for this kit, importing Selectors replaced the destination selector set. Importing into an established site can therefore affect existing designs.&lt;/p&gt;

&lt;p&gt;The layouts are imported individually. This is not an automatic site installer and does not configure a working contact form or payments.&lt;/p&gt;

&lt;p&gt;The historical report covers Oxygen 6.2.0-beta.9 and 6.2 RC1. It is not a new complete import test on every later version. Oxygen Classic is outside this kit's supported workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give each page one job
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Page&lt;/th&gt;
&lt;th&gt;Question it should answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Home&lt;/td&gt;
&lt;td&gt;What do you do, and who is it for?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Services&lt;/td&gt;
&lt;td&gt;What work is included, and what happens next?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;About&lt;/td&gt;
&lt;td&gt;Who will the customer work with?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contact&lt;/td&gt;
&lt;td&gt;How can someone start a useful conversation?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Replace fictional claims with statements you can support. A polished template does not make an invented case study real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Import page bodies and shared templates separately
&lt;/h2&gt;

&lt;p&gt;Create the four WordPress pages. On an empty page, connect the Design Set through Oxygen's library workflow and select the matching Service Website Kit layout. Follow the access page's import instructions, including the selector warning.&lt;/p&gt;

&lt;p&gt;Import the header and footer as their own Oxygen templates. Check their display conditions so another matching template does not produce a second header or footer.&lt;/p&gt;

&lt;p&gt;The four page layouts form the page bodies. A page-body import does not also install the navigation around it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpb1flztnkiw6jq65s33v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpb1flztnkiw6jq65s33v.jpg" alt="Actual rendered Home example from the kit, captured 13 October 2026" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The example business and its services are fictional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replace destinations as well as labels
&lt;/h2&gt;

&lt;p&gt;A menu can say “Contact” while still pointing at an example preview URL. Follow every navigation item and call to action on the saved frontend pages.&lt;/p&gt;

&lt;p&gt;If your slugs differ from the imported examples, choose the real WordPress page in the link control. Set the actual homepage under Settings → Reading when the project is ready.&lt;/p&gt;

&lt;p&gt;Replace the &lt;a href="mailto:hello@example.com"&gt;hello@example.com&lt;/a&gt; placeholder. If you add a form, send a real test enquiry and confirm that it arrives at the intended inbox before describing the contact route as working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check your content, not just the starter
&lt;/h2&gt;

&lt;p&gt;Try the final service names, a long heading and a narrow viewport. Check keyboard navigation, visible focus and browser zoom. Shared classes affect every element using them, so review other pages after a class change.&lt;/p&gt;

&lt;p&gt;Keep a short handover record: which pages were checked, which links were followed and whether the contact test was received. Record remaining work instead of marking the whole site ready because an import succeeded.&lt;/p&gt;

&lt;p&gt;The free &lt;a href="https://benjaminolsen.dev/oxygen-general-design-library/?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=tools_tutorials_202610&amp;amp;utm_content=oxygen_kit" rel="noopener noreferrer"&gt;kit and access instructions&lt;/a&gt; explain import scope and known limitations. Start with the empty staging copy, adapt one page, then repeat the workflow across the other three.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I maintain the linked tool or kit. This article was prepared with AI assistance. Practical checks are identified separately from illustrative examples; verify the result in your own project.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Stress-test a card with longer content before adding breakpoints</title>
      <dc:creator>Benjamin Olsen</dc:creator>
      <pubDate>Sat, 17 Oct 2026 10:47:21 +0000</pubDate>
      <link>https://dev.to/benjaminolsen/stress-test-a-card-with-longer-content-before-adding-breakpoints-kpp</link>
      <guid>https://dev.to/benjaminolsen/stress-test-a-card-with-longer-content-before-adding-breakpoints-kpp</guid>
      <description>&lt;p&gt;A card that fits “Design” may fail when its title becomes “Website design for international service businesses.”&lt;/p&gt;

&lt;p&gt;Before adding another breakpoint, change the content. Longer headings, translated labels and a missing image can reveal assumptions that resizing the viewport alone will miss.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with a deliberately fragile component
&lt;/h2&gt;

&lt;p&gt;Paste this into a static HTML preview or a local file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;font&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.5&lt;/span&gt; &lt;span class="n"&gt;system-ui&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;420px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#777&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;margin-block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Design&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;A practical service for your next website project.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Read more&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At a 375px viewport, the page has only 343px after its two 16px gutters. A 420px card cannot fit. This follows from the example's dimensions; it is not a new measured test result.&lt;/p&gt;

&lt;p&gt;A smaller font would hide the wrong problem. The card itself is wider than the available space.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix the constraint you found
&lt;/h2&gt;

&lt;p&gt;Replace the card rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;inline-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;max-inline-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;420px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#777&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then test a long title and a longer link label. Avoid a fixed card height unless the design has a clear reason for one and an explicit strategy for overflowing content.&lt;/p&gt;

&lt;p&gt;The width change makes this example fit the available inline space. It does not prove that a larger component with images or nested grids has no other problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compare the same content at three widths
&lt;/h2&gt;

&lt;p&gt;I use 375, 768 and 1200px as a quick comparison set. At each width, inspect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether anything extends beyond the content area.&lt;/li&gt;
&lt;li&gt;Whether text overlaps or clips, even without a horizontal scrollbar.&lt;/li&gt;
&lt;li&gt;Whether longer labels wrap in a useful way.&lt;/li&gt;
&lt;li&gt;Whether hiding an image leaves an awkward gap or removes needed information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are starting points. Your project may need narrower or intermediate checks too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep automated overflow results in their lane
&lt;/h2&gt;

&lt;p&gt;On 17 October 2026, the built-in example in my Responsive Content Tester was checked with its Long translation preset. It rendered all three comparison widths and reported no horizontal overflow at any of them.&lt;/p&gt;

&lt;p&gt;That result applies to that example. It says nothing about the deliberately fragile card above until you run it, and it does not certify clipping, readability or accessibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try content variations
&lt;/h2&gt;

&lt;p&gt;I maintain the free &lt;a href="https://benjaminolsen.dev/responsive-content-tester/?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=tools_tutorials_202610&amp;amp;utm_content=responsive_card" rel="noopener noreferrer"&gt;Responsive Content Tester&lt;/a&gt;. Paste HTML with inline CSS, apply the longer-content preset, compare Original and With tests, then run the three-width comparison.&lt;/p&gt;

&lt;p&gt;The preview blocks scripts and external files and does not fetch a live website URL. It is useful for a static layout experiment, not for reproducing an application's complete runtime or testing another browser engine.&lt;/p&gt;

&lt;p&gt;After the experiment, apply the relevant change in your actual project and test the saved page again. The preview helps identify a question; the real page provides the final context.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I maintain the linked tool or kit. This article was prepared with AI assistance. Practical checks are identified separately from illustrative examples; verify the result in your own project.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>testing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>A passing contrast ratio is the start of a button check</title>
      <dc:creator>Benjamin Olsen</dc:creator>
      <pubDate>Sat, 17 Oct 2026 10:47:08 +0000</pubDate>
      <link>https://dev.to/benjaminolsen/a-passing-contrast-ratio-is-the-start-of-a-button-check-15ai</link>
      <guid>https://dev.to/benjaminolsen/a-passing-contrast-ratio-is-the-start-of-a-button-check-15ai</guid>
      <description>&lt;p&gt;A button can pass a color-contrast calculation and still be difficult to use.&lt;/p&gt;

&lt;p&gt;The calculation answers a narrow question: how much luminance contrast exists between the specified foreground and background colors? It does not tell you whether the control has a useful label, visible focus or enough space when text grows.&lt;/p&gt;

&lt;p&gt;Here is a small workflow for keeping those checks separate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Begin with a known pair
&lt;/h2&gt;

&lt;p&gt;Use black text on white as a sanity check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Text:       #000000
Background: #ffffff
Contrast:   21:1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current version of my checker returned 21.000:1 for this pair. That is a known example, not a claim that the whole tool or your website has passed an accessibility audit.&lt;/p&gt;

&lt;p&gt;Now enter the exact colors used by your button. Do not estimate them from a screenshot if the CSS values are available.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html" rel="noopener noreferrer"&gt;W3C explanation of minimum contrast&lt;/a&gt; describes AA requirements for text: generally 4.5:1, or 3:1 for qualifying large text. Large text means at least 18pt, or 14pt bold—approximately 24 CSS px or 18.67 CSS px respectively. A small button label does not qualify simply because its font looks bold.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the states you render
&lt;/h2&gt;

&lt;p&gt;Create a short record before changing colors:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Text color&lt;/th&gt;
&lt;th&gt;Background&lt;/th&gt;
&lt;th&gt;Other check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Default&lt;/td&gt;
&lt;td&gt;Actual CSS value&lt;/td&gt;
&lt;td&gt;Actual CSS value&lt;/td&gt;
&lt;td&gt;Label is readable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hover&lt;/td&gt;
&lt;td&gt;Actual CSS value&lt;/td&gt;
&lt;td&gt;Actual CSS value&lt;/td&gt;
&lt;td&gt;Label remains readable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keyboard focus&lt;/td&gt;
&lt;td&gt;Actual CSS value&lt;/td&gt;
&lt;td&gt;Actual CSS value&lt;/td&gt;
&lt;td&gt;Focus is visible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If hover changes the background, check the new pair. If it changes opacity, the rendered result depends on what is behind it; an opaque HEX-pair calculation is no longer the complete picture.&lt;/p&gt;

&lt;p&gt;Keep focus visible without relying on hover. This gives a starting point to inspect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.action&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.75rem&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;currentColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.action&lt;/span&gt;&lt;span class="nd"&gt;:focus-visible&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;outline-offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The outline still needs to be checked against the actual surrounding surface. This snippet is not a universal focus-indicator solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the non-color checks
&lt;/h2&gt;

&lt;p&gt;Use Tab to reach the control and confirm that focus is visible. Activate it using the expected keyboard interaction for its element type. Increase text size and inspect wrapping. Read the label out of context: “Send project enquiry” communicates more than “Click here.”&lt;/p&gt;

&lt;p&gt;Use a button for an action and a link for navigation. A good color pair cannot repair the wrong interaction semantics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Record what passed
&lt;/h2&gt;

&lt;p&gt;Write “text/background pair passes AA normal-text contrast,” rather than “button is accessible.” The narrower statement tells the next person which question was actually answered.&lt;/p&gt;

&lt;p&gt;I maintain the free &lt;a href="https://benjaminolsen.dev/contrast-checker/?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=tools_tutorials_202610&amp;amp;utm_content=contrast_button" rel="noopener noreferrer"&gt;Color Contrast Checker&lt;/a&gt;. It compares solid, opaque sRGB colors and previews the pair. Images, gradients, transparency, keyboard behavior and the rest of the page need their own review.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I maintain the linked tool or kit. This article was prepared with AI assistance. Practical checks are identified separately from illustrative examples; verify the result in your own project.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>css</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a fluid heading from two sizes and two viewport widths</title>
      <dc:creator>Benjamin Olsen</dc:creator>
      <pubDate>Sat, 17 Oct 2026 10:45:12 +0000</pubDate>
      <link>https://dev.to/benjaminolsen/build-a-fluid-heading-from-two-sizes-and-two-viewport-widths-10je</link>
      <guid>https://dev.to/benjaminolsen/build-a-fluid-heading-from-two-sizes-and-two-viewport-widths-10je</guid>
      <description>&lt;p&gt;You do not need a different font-size rule at every breakpoint to make a heading grow with the viewport. Choose its two acceptable sizes and the range over which it should grow.&lt;/p&gt;

&lt;p&gt;For this example, a service-page heading should be 28px at 375px and 44px at 1280px. Those are design decisions for this example, not universal typography rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calculate the middle expression
&lt;/h2&gt;

&lt;p&gt;The size increases by 16px across a 905px viewport range:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;slope = (44 - 28) / (1280 - 375)
      = 16 / 905
      ≈ 0.01767956
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because 1vw is one hundredth of the viewport width, the viewport term becomes approximately 1.767956vw.&lt;/p&gt;

&lt;p&gt;Subtract its contribution at the small viewport to find the constant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;28 - (0.01767956 × 375) ≈ 21.370166px
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a 16px root size, the bounds are 1.75rem and 2.75rem. The constant is approximately 1.335635rem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.service-heading&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.75rem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1.335635rem&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1.767956vw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2.75rem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;max-inline-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;22ch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/clamp" rel="noopener noreferrer"&gt;MDN's definition of clamp()&lt;/a&gt;, the three positions are the lower bound, preferred expression and upper bound. The middle expression can grow while the bounds keep the result within the chosen range.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check more than the endpoints
&lt;/h2&gt;

&lt;p&gt;At a 16px root size, the rounded expression should produce approximately:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Viewport&lt;/th&gt;
&lt;th&gt;Font size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;320px&lt;/td&gt;
&lt;td&gt;28px, held by the minimum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;375px&lt;/td&gt;
&lt;td&gt;28px&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;768px&lt;/td&gt;
&lt;td&gt;34.95px&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1280px&lt;/td&gt;
&lt;td&gt;44px&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1440px&lt;/td&gt;
&lt;td&gt;44px, held by the maximum&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These values are calculated from the expression. The Section heading preset in my generator was also checked with the 375–1280px range. This is not physical-device testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make wrapping visible
&lt;/h2&gt;

&lt;p&gt;Try both headings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Website design
Website design for service businesses with growing teams
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second may wrap into several lines. If it collides with a fixed-height container, the font-size formula is not necessarily the problem. Inspect the container's height, width and spacing too.&lt;/p&gt;

&lt;p&gt;The 22ch line-length limit is a starting point. Change it when your actual font and content need something different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check text resizing in the real layout
&lt;/h2&gt;

&lt;p&gt;The 28px and 44px values assume a 16px root size. A different root changes the REM terms. Zoom and text-resizing preferences can expose clipping or unexpected wrapping.&lt;/p&gt;

&lt;p&gt;Keep the root size consistent with your project, then test larger text and zoom on the actual page. A smooth formula can still live inside a layout that cannot grow.&lt;/p&gt;

&lt;p&gt;I maintain the free &lt;a href="https://benjaminolsen.dev/css-clamp-generator/?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=tools_tutorials_202610&amp;amp;utm_content=clamp_heading" rel="noopener noreferrer"&gt;CSS Clamp Generator&lt;/a&gt;. Use its Section heading preset, preview common widths and copy the expression, or use the calculation above directly. The useful part is choosing and checking the bounds deliberately.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I maintain the linked tool or kit. This article was prepared with AI assistance. Practical checks are identified separately from illustrative examples; verify the result in your own project.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Review an internal-link suggestion before it becomes a task</title>
      <dc:creator>Benjamin Olsen</dc:creator>
      <pubDate>Sat, 17 Oct 2026 10:44:28 +0000</pubDate>
      <link>https://dev.to/benjaminolsen/review-an-internal-link-suggestion-before-it-becomes-a-task-4ad2</link>
      <guid>https://dev.to/benjaminolsen/review-an-internal-link-suggestion-before-it-becomes-a-task-4ad2</guid>
      <description>&lt;p&gt;An internal-link suggestion is useful only when you can explain why a reader should follow it.&lt;/p&gt;

&lt;p&gt;Here is a small example you can reproduce with a spreadsheet. Three pages are enough to expose a common mistake: treating topic similarity as permission to add a link anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with an inventory, not a list of keywords
&lt;/h2&gt;

&lt;p&gt;Use three fictional pages:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Page&lt;/th&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;th&gt;Already links to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;/design/ — Website design&lt;/td&gt;
&lt;td&gt;Web design&lt;/td&gt;
&lt;td&gt;/cost/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/cost/ — Website project cost&lt;/td&gt;
&lt;td&gt;Web design&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/privacy/ — Privacy policy&lt;/td&gt;
&lt;td&gt;Legal&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The design page explains a website project. The cost page discusses planning its budget. The privacy page explains personal data.&lt;/p&gt;

&lt;p&gt;There is already a design → cost link. That does not mean the reverse connection exists. It also does not mean every page mentioning a website belongs in the same linking plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review one possible connection
&lt;/h2&gt;

&lt;p&gt;A useful candidate is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source: /cost/
Destination: /design/
Anchor: website design
Placement: the paragraph explaining which design work the budget includes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shared subject gives us a reason to inspect the candidate. The paragraph supplies the reason to add it: a reader comparing costs may need to understand the work included.&lt;/p&gt;

&lt;p&gt;Before accepting it, ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does the destination answer the question raised by this paragraph?&lt;/li&gt;
&lt;li&gt;Would the sentence still read naturally without the link?&lt;/li&gt;
&lt;li&gt;Does the anchor describe the destination?&lt;/li&gt;
&lt;li&gt;Is the connection already present in the actual page?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not add a privacy → design link just to make the inventory more connected. Legal text is not automatically a useful route into a service explanation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write an actionable task
&lt;/h2&gt;

&lt;p&gt;“Add more internal links” leaves the implementation to someone else's guesswork. Save the source, destination, anchor and placement note together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source,target,anchor,status,note
/cost/,/design/,website design,planned,Link where the paragraph explains the design work included
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simplified CSV is a suggested handover format, not a claim that every tool imports these exact columns. Keep the status honest: planned means the link is still absent from the website.&lt;/p&gt;

&lt;p&gt;After editing the site, follow the link on the saved frontend page and re-read its surrounding sentence. Only then mark implementation complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try the worked example
&lt;/h2&gt;

&lt;p&gt;I maintain the free &lt;a href="https://benjaminolsen.dev/internal-link-planner/?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=tools_tutorials_202610&amp;amp;utm_content=planner_review" rel="noopener noreferrer"&gt;Internal Link Planner&lt;/a&gt;. Its &lt;a href="https://benjaminolsen.dev/internal-link-planner/#three-page-example" rel="noopener noreferrer"&gt;three-page example&lt;/a&gt; includes the input inventory and an exported one-task plan.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk8pmpohl47fb44kv6p6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk8pmpohl47fb44kv6p6g.png" alt="Internal Link Planner showing the three-page worked example" width="799" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The planner uses page information you supply. It does not crawl your website or publish links for you. Review its match evidence, adjust the anchor and export the tasks you actually intend to implement. Browser-saved work also needs an export if you want a portable copy.&lt;/p&gt;

&lt;p&gt;For a first run, aim for one defensible task. Can someone implement it without guessing where the link belongs?&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I maintain the linked tool or kit. This article was prepared with AI assistance. Practical checks are identified separately from illustrative examples; verify the result in your own project.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why page 2 repeats the same posts in an Oxygen loop</title>
      <dc:creator>Benjamin Olsen</dc:creator>
      <pubDate>Sat, 17 Oct 2026 09:37:37 +0000</pubDate>
      <link>https://dev.to/benjaminolsen/why-page-2-repeats-the-same-posts-in-an-oxygen-loop-2155</link>
      <guid>https://dev.to/benjaminolsen/why-page-2-repeats-the-same-posts-in-an-oxygen-loop-2155</guid>
      <description>&lt;p&gt;A pagination link can change the URL while leaving the cards exactly as they were. That happened in a private Oxygen 6.2.0-beta.9 test: a static Text query returned six posts on page 1, and clicking page 2 repeated those same six posts.&lt;/p&gt;

&lt;p&gt;Switching that example to Custom → Edit Query returned the correct seventh post. Here is the small test and the settings used, so you can check the result in your own project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make page 2 easy to verify
&lt;/h2&gt;

&lt;p&gt;Create seven published posts in a private test category called Loop guide demo. Use different titles, manual excerpts and publication dates. Seven is intentional: six matching posts would not leave anything for a second page.&lt;/p&gt;

&lt;p&gt;Create a Component for one card. Bind its heading to Post Title, its excerpt to Post Excerpt and its Read guide URL to Post Permalink. Keep the fields in the current-post context, rather than selecting one fixed article. The loop supplies the current item when the Component is repeated.&lt;/p&gt;

&lt;p&gt;On a normal page, add Post Loop Builder. In Content → Repeated Block, select the card Component and use article as the repeated item's tag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the visual Custom query
&lt;/h2&gt;

&lt;p&gt;Open Content → Query → Custom → Edit Query and enter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source: Post Types; Include: Posts.&lt;/li&gt;
&lt;li&gt;Posts per page: 6.&lt;/li&gt;
&lt;li&gt;Total posts and Offset: leave both blank.&lt;/li&gt;
&lt;li&gt;Condition: Has Taxonomy → is one of → Loop guide demo, from Categories.&lt;/li&gt;
&lt;li&gt;Order By: Date; Order: Descending; Date: All.&lt;/li&gt;
&lt;li&gt;Ignore sticky posts: enabled. Ignore current post: off for this normal-page example.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apply the query. Under Content → Pagination, choose Numbers and keep Filter Bar disabled for this recipe. Save, then open the saved frontend.&lt;/p&gt;

&lt;p&gt;Do not set Total posts to 6 when you expect seven results across two pages. That cap would remove the extra result you need to test pagination.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the content, not only the address
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5y9iken8gu1l0a1ckza8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5y9iken8gu1l0a1ckza8.png" alt="Six different guide cards on the first page." width="799" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first page should contain the six newest matching posts. Click 2 below the grid and compare the cards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0wpobmre9rq204z75961.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0wpobmre9rq204z75961.png" alt="The second page contains only the seventh post, CSS spacing basics." width="799" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this fixture the seventh post was CSS spacing basics. Selecting 1 returned to the six newer cards. Two Read guide links were also followed, and each destination heading matched the selected card.&lt;/p&gt;

&lt;p&gt;If every card links to one article, inspect the Component's URL binding before changing the query. A literal destination stays the same for every repetition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check an empty category and smaller screens
&lt;/h2&gt;

&lt;p&gt;Create a simple empty-state Component containing “No guides in this category yet.” Select it under Content → Repeated Block → Advanced → When Empty. On a separate test copy of the page, change the query condition to a category without any posts. The expected result is the message, with no cards or page-number links.&lt;/p&gt;

&lt;p&gt;The tested Grid layout used three items per row on Desktop, two at Tablet Portrait, and one at Phone Landscape, with a 24px gap. The card supplied its own inner padding, so the loop's Post padding was set to 0px on every side.&lt;/p&gt;

&lt;p&gt;Those responsive overrides applied at 1023px and 767px in this installation. Check the breakpoints configured on your own site. Confirm that longer titles fit and that the saved frontend does not scroll horizontally at phone widths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the scope of the fix clear
&lt;/h2&gt;

&lt;p&gt;This is a normal-page custom query. An archive's primary loop should preserve its inherited main query instead of copying these category-specific settings.&lt;/p&gt;

&lt;p&gt;The fixture used native Oxygen elements and Components prepared programmatically. The Query Builder settings were inspected and saved in the editor, and the frontend was tested at 390, 820, 1440 and 1920px. The local editor canvas remained blank, so the full manual construction workflow was not verified. This is a tested workaround for this fixture and version, not a claim that every Text query or every Oxygen release behaves the same way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://benjaminolsen.dev/oxygen-post-loop-builder/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=growth_6w_2026q4&amp;amp;utm_content=post-loop-pagination" rel="noopener noreferrer"&gt;Original recipe with query screenshot and full test notes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article was prepared with AI assistance from the documented test example.&lt;/p&gt;

</description>
      <category>oxygen</category>
      <category>wordpress</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>One Oxygen template, different page content</title>
      <dc:creator>Benjamin Olsen</dc:creator>
      <pubDate>Sat, 17 Oct 2026 09:36:17 +0000</pubDate>
      <link>https://dev.to/benjaminolsen/one-oxygen-template-different-page-content-44jn</link>
      <guid>https://dev.to/benjaminolsen/one-oxygen-template-different-page-content-44jn</guid>
      <description>&lt;p&gt;Two service pages can share an introduction strip and a contact section without sharing every sentence. In Oxygen 6, Template Content Area supplies the place where each page's own layout appears inside that shared frame.&lt;/p&gt;

&lt;p&gt;The useful distinction is where you make an edit. Shared wording belongs in the template. A service's own heading, description and images belong in the individual page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with two deliberately different pages
&lt;/h2&gt;

&lt;p&gt;Use a private test website and create Web design and Website maintenance. Give each page a different H1 and a short description. Make the difference obvious enough that repeated content would be easy to spot.&lt;/p&gt;

&lt;p&gt;Next, create a template for Pages under Oxygen → Templates. Name it Service pages and restrict its conditions to those two test pages. Limiting the test keeps a shared change from unexpectedly reaching the rest of your website.&lt;/p&gt;

&lt;p&gt;Build the parts that should repeat in that template: for example, a service strip above the content and a next-step section below it. If separate header and footer templates already supply the navigation, keep those there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the page-specific region
&lt;/h2&gt;

&lt;p&gt;While editing the template, find Template Content Area in the Add panel's Dynamic category. Place one between the shared sections, then save the template.&lt;/p&gt;

&lt;p&gt;Open Web design as an individual page in Oxygen. Its own elements belong in the content area supplied by the template. Repeat this with Website maintenance, using that page's different content. You do not type both services' descriptions into the Template Content Area settings.&lt;/p&gt;

&lt;p&gt;Choose the HTML structure deliberately. If the surrounding template already provides a main landmark, use a div or section for the content region instead of adding another nested main element.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the saved result
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0zq0eczzoh9m9cy14lwh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0zq0eczzoh9m9cy14lwh.png" alt="Web design has its own heading and description between the shared sections." width="799" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7itctq51eetgjyl3t2cn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7itctq51eetgjyl3t2cn.png" alt="Website maintenance uses the same frame with different page content." width="799" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These screenshots show fictional test pages. The blue areas belong to their common template; the white region contains each page's own content.&lt;/p&gt;

&lt;p&gt;The private frontend test changed the shared strip to “Shared service page layout”. That wording changed on both pages, while their individual headings stayed different. An unrelated About page stayed outside the template's conditions.&lt;/p&gt;

&lt;p&gt;Try the same small test in your project. Open both frontend URLs, change one shared sentence, save, and compare again. Then inspect a phone width with a longer heading. A successful editor preview alone does not establish the final result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three quick diagnoses
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If both pages show the same description, check whether it was added to the shared template. Move the unique copy into the individual pages.&lt;/li&gt;
&lt;li&gt;If a page is blank, confirm the matching template contains Template Content Area and the page has saved Oxygen content of its own.&lt;/li&gt;
&lt;li&gt;If the shared frame is missing, check the template's location, conditions and priority against that exact page URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Design Set serves a different purpose: it imports saved layouts. Importing one does not automatically decide which template applies to your pages.&lt;/p&gt;

&lt;p&gt;The source example was checked on 16 October 2026 with Oxygen 6.2.0-beta.9 and WordPress 7.1.3 at 390px and 1440px in desktop Chromium. It was a native-element and frontend check, not a full manual test of every editor control or all versions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://benjaminolsen.dev/oxygen-template-content-area/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=growth_6w_2026q4&amp;amp;utm_content=template-content-area" rel="noopener noreferrer"&gt;Original walkthrough, test scope and official references&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article was prepared with AI assistance from the documented test example.&lt;/p&gt;

</description>
      <category>oxygen</category>
      <category>tutorial</category>
      <category>wordpress</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
