diff options
Diffstat (limited to 'build/tabbed-content/index.html')
-rw-r--r-- | build/tabbed-content/index.html | 149 |
1 files changed, 77 insertions, 72 deletions
diff --git a/build/tabbed-content/index.html b/build/tabbed-content/index.html index 295a712..cfabe83 100644 --- a/build/tabbed-content/index.html +++ b/build/tabbed-content/index.html @@ -1,102 +1,94 @@ <!doctype html> -<html lang="en" id="top"> +<html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="data:,"> <title>Tabbed Content Without JavaScript</title> - <link href="https://bt.ht/atom.xml" type="application/atom+xml" rel="alternate" title="Atom feed for blog posts" /> - <style>*{box-sizing:border-box;}body{font-family:sans-serif;margin:0 auto;max-width:650px;padding:1rem;}img{max-width:100%;}pre{overflow:auto;}table{text-align:left;width:100%;}</style> + <link href="/atom.xml" type="application/atom+xml" rel="alternate" title="Atom feed for blog posts" /> + <link href="/rss.xml" type="application/rss+xml" rel="alternate" title="RSS feed for blog posts" /> +<style>*{box-sizing:border-box;}body{font-family:sans-serif;line-height:1.33;margin:0 auto;max-width:650px;padding:1rem;}img{max-width:100%;}pre{border:1px solid;overflow:auto;padding:5px;}table{text-align:left;width:100%;}.footnotes{font-size:90%;}</style> </head> <nav> - <a href="#menu">Menu ↓</a> + <a href="#menu">Menu ↓</a> </nav> <main> -<h1>Tabbed Content Without JavaScript</h1> +<h1 id="tabbed-content-without-javascript">Tabbed Content Without JavaScript</h1> + <p>2019-01-28</p> + <p>Creating tabs is a fairly trivial and common practice in web design, but many times it requires JavaScript to properly implement. Fortunately it <em>is</em> possible to create tabbed content with only using CSS.</p> + <p><img src="/public/images/tabbed-content.png" alt="Tabbed elements with only CSS" /></p> + <p><a href="https://codepen.io/bradleytaunt/pen/abjmayw">Live CodePen Example</a></p> -<hr /> -<p><div class="message"> -<p><strong>Sidenote:</strong></p> -<p>While this method is semantic and accessible, you might consider using a pre-existing plugin for tabbed data.</p> -<p>This component tends to feel a little "stiff" compared to more fleshed out variations available. This pure CSS version is better suited as a fallback for when users have disabled JavaScript.</p> -</div></p> -<h2>The HTML</h2> + +<hr/> + +<h2 id="the-html">The HTML</h2> + <p>The skeleton for this component is fairly basic - we just need the following structure:</p> + <ol> -<li>Parent element for each tab item</li> -<li>Default radio input</li> -<li>Label linked to corresponding input</li> -<li>Inner content associated with each tab item</li> +<li><p>Parent element for each tab item</p></li> +<li><p>Default radio input</p></li> +<li><p>Label linked to corresponding input</p></li> +<li><p>Inner content associated with each tab item</p></li> </ol> -<pre><code><!-- Simple main container for all elements --> -<div class="tabs"> - <!-- Parent container holding for individual tab item --> - <div class="tab-item"> +<p>Full HTML for reference:</p> - <!-- Default radio input --> - <input class="tab-input" type="radio" name="tabs" id="tab-1"> +<pre><code><div class="tabs"> - <!-- Label connected to radio input via `id` and `for` attributes --> - <label class="tab-label" for="tab-1">Tab 1</label> + <div class="tab-item"> + <input class="tab-input" type="radio" name="tabs" id="tab-1"> + <label class="tab-label" for="tab-1">Tab 1</label> + <div class="tab-content">Content goes here</div> + </div> - <!-- Full inner content of current tab item --> - <div class="tab-content">Content goes here</div> + <div class="tab-item"> + <input class="tab-input" type="radio" name="tabs" id="tab-2"> + <label class="tab-label" for="tab-2">Tab 2</label> + <div class="tab-content">Content goes here</div> + </div> - </div> + <div class="tab-item"> + <input class="tab-input" type="radio" name="tabs" id="tab-3"> + <label class="tab-label" for="tab-3">Tab 3</label> + <div class="tab-content">Content goes here</div> + </div> -</div> -</code></pre> -<p>Full HTML for reference:</p> -<pre><code><div class="tabs"> - - <div class="tab-item"> - <input class="tab-input" type="radio" name="tabs" id="tab-1"> - <label class="tab-label" for="tab-1">Tab 1</label> - <div class="tab-content">Content goes here</div> - </div> - - <div class="tab-item"> - <input class="tab-input" type="radio" name="tabs" id="tab-2"> - <label class="tab-label" for="tab-2">Tab 2</label> - <div class="tab-content">Content goes here</div> - </div> - - <div class="tab-item"> - <input class="tab-input" type="radio" name="tabs" id="tab-3"> - <label class="tab-label" for="tab-3">Tab 3</label> - <div class="tab-content">Content goes here</div> - </div> - -</div> +</div> </code></pre> -<h2>The CSS</h2> + +<h2 id="the-css">The CSS</h2> + <p>First, we need to set each <code>input</code>, <code>label</code> and inner content into their own parent containers:</p> -<pre><code>/* Main parent that holds all contents */ + +<pre><code>/* Main parent that holds all contents */ .tabs { height: 100%; min-height: 250px; position: relative; } -/* Each tab items (includes heading & content) */ +/* Each tab items (includes heading & content) */ .tab-item { display: inline; } </code></pre> + <p>Next, we will hide the default <code>radio</code> input and design our labels to resemble a basic web tab element. The <code>z-index</code> property on the label is important for how we will be stacking our content on the z-axis (labels above inner content for example).</p> -<pre><code>/* Hide the default radio inputs */ + +<pre><code>/* Hide the default radio inputs */ .tab-input { position: absolute; visibility: hidden; } -/* The main tab headings */ +/* The main tab headings */ .tab-label { background: white; box-shadow: inset 0 -4px 4px rgba(0,0,0,0.02); @@ -111,8 +103,10 @@ z-index: 0; } </code></pre> -<p>The main inner content of each tab needs to have an <code>absolute</code> position set as it's default, since the one currently selected will switch to <code>relative</code> on mobile (more on that in a moment):</p> -<pre><code>/* The inner tab content */ + +<p>The main inner content of each tab needs to have an <code>absolute</code> position set as it’s default, since the one currently selected will switch to <code>relative</code> on mobile (more on that in a moment):</p> + +<pre><code>/* The inner tab content */ .tab-content { background: white; bottom: 0; @@ -126,8 +120,10 @@ z-index: 0; } </code></pre> + <p>The final step is just telling the browser to style both the <code>label</code> and inner content of the currently selected radio <code>input</code>:</p> -<pre><code>/* Style the currently selected tab label */ + +<pre><code>/* Style the currently selected tab label */ .tab-input:checked + .tab-label { border: 1px solid #eee; border-bottom: 0; @@ -136,32 +132,34 @@ z-index: 2; } -/* Show the currently selected tab content */ +/* Show the currently selected tab content */ .tab-input:checked ~ .tab-content { border: 1px solid #eee; z-index: 1; } </code></pre> -<p>It's as simple as that! For reference, here is the entire CSS file for easier access:</p> -<pre><code>/* Main parent that holds all contents */ + +<p>It’s as simple as that! For reference, here is the entire CSS file for easier access:</p> + +<pre><code>/* Main parent that holds all contents */ .tabs { height: 100%; min-height: 250px; position: relative; } -/* Each tab items (includes heading & content) */ +/* Each tab items (includes heading & content) */ .tab-item { display: inline; } -/* Hide the default radio inputs */ +/* Hide the default radio inputs */ .tab-input { position: absolute; visibility: hidden; } -/* The main tab headings */ +/* The main tab headings */ .tab-label { background: white; box-shadow: inset 0 -4px 4px rgba(0,0,0,0.02); @@ -176,7 +174,7 @@ z-index: 0; } -/* The inner tab content */ +/* The inner tab content */ .tab-content { background: white; bottom: 0; @@ -190,7 +188,7 @@ z-index: 0; } -/* Style the currently selected tab label */ +/* Style the currently selected tab label */ .tab-input:checked + .tab-label { border: 1px solid #eee; border-bottom: 0; @@ -199,14 +197,17 @@ z-index: 2; } -/* Show the currently selected tab content */ +/* Show the currently selected tab content */ .tab-input:checked ~ .tab-content { border: 1px solid #eee; z-index: 1; } </code></pre> -<h2>Don't forget about mobile</h2> + +<h2 id="dont-forget-about-mobile">Don’t forget about mobile</h2> + <p>With only a few extra lines of CSS we can ensure that our custom tabs will stack on top of each other and look solid on mobile devices:</p> + <pre><code>@media(max-width:38em) { .tab-label { display: block; @@ -223,9 +224,13 @@ } } </code></pre> -<h2>One minor caveat</h2> -<p>Even though I'm a pretty big fan of implementing tabs this way, there is a small drawback:</p> -<p>The <code>height</code> of the inner content doesn't grow dynamically since it defaults as <code>absolute</code>, so a <code>min-height</code> or <code>height</code> value is required on the parent element. This could become a problem in certain situations where you don't have the luxury of setting a static height.</p> + +<h2 id="one-minor-caveat">One minor caveat</h2> + +<p>Even though I’m a pretty big fan of implementing tabs this way, there is a small drawback:</p> + +<p>The <code>height</code> of the inner content doesn’t grow dynamically since it defaults as <code>absolute</code>, so a <code>min-height</code> or <code>height</code> value is required on the parent element. This could become a problem in certain situations where you don’t have the luxury of setting a static height.</p> + <p>Other than that, enjoy building some JavaScript-free tabs!</p> <footer role="contentinfo"> <h2>Menu Navigation</h2> |