FAB without JavaScript

Just after my daughter was born we needed a simple way to track “Baby Habits” (Read: Eat, Poop, Wee, Sleep, and maybe a bit of Vom). During my baby duties when the baby was asleep I built Akachan.app to help us keep on top of things.
I wanted this app to load instantly, and given that JavaScript is one of the biggest contributors to a slow page load, I gave myself the challenge to build Akachan as a SPA without client-side JS (more in another post), which for the most part I was able to do this with traditional POST’s and a hefty amount of Service Worker logic.


This content originally appeared on Modern Web Development with Chrome and was authored by Paul Kinlan

<p>Just after my daughter was born we needed a simple way to track "Baby Habits" (Read: Eat, Poop, Wee, Sleep, and maybe a bit of Vom). During my baby duties when the baby was asleep I built <a href="https://akachan.app/">Akachan.app</a> to help us keep on top of things.</p> <p>I wanted this app to load instantly, and given that JavaScript is one of the biggest contributors to a slow page load, I gave myself the challenge to build Akachan as a SPA without client-side JS (more in another post), which for the most part I was able to do this with traditional POST's and a hefty amount of Service Worker logic.</p> <p>There was one challenge, I wanted a Material Design like Floating Action Button (FAB) in my page that gave you the ability to quickly add any of the babies activities, but without adding any additional JavaScript.</p> <figure><video src="https://paul.kinlan.me/videos/2020-09-23-fab-without-javascript-0.mp4" alt="Floating Action Button in action" controls></video></figure> <p>All of the solutions I could find required client-side JavaScript to function and I didn't want that, so I built one without any.</p> <p>The solution was to have a 'menu' with an id of "add-nav" and then to use two anchors (one for the open state and one for the closed state) with an href of #add-nav and #remove-nav, and then using how the browser manages anchor based navigation by managing the visibility of the anchors and menus with CSS and the ":target" selector.</p> <h3 id="html">HTML</h3> <div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-HTML" data-lang="HTML"><<span style="color:#f92672">nav</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">"add-nav"</span>> <<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">"/feeds/new"</span> <span style="color:#a6e22e">title</span><span style="color:#f92672">=</span><span style="color:#e6db74">"Add a feed"</span>>?</<span style="color:#f92672">a</span>> <<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">"/sleeps/new"</span> <span style="color:#a6e22e">title</span><span style="color:#f92672">=</span><span style="color:#e6db74">"Add a Sleep"</span>>?</<span style="color:#f92672">a</span>> <<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">"/poops/new"</span> <span style="color:#a6e22e">title</span><span style="color:#f92672">=</span><span style="color:#e6db74">"Add a Poop"</span>>?</<span style="color:#f92672">a</span>> <<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">"/wees/new"</span> <span style="color:#a6e22e">title</span><span style="color:#f92672">=</span><span style="color:#e6db74">"Add a Wee"</span>>⛲️</<span style="color:#f92672">a</span>> </<span style="color:#f92672">nav</span>> <<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">"#remove-nav"</span>> <<span style="color:#f92672">img</span> <span style="color:#a6e22e">src</span><span style="color:#f92672">=</span><span style="color:#e6db74">"/images/icons/ui/remove_white_18dp.svg"</span> <span style="color:#a6e22e">alt</span><span style="color:#f92672">=</span><span style="color:#e6db74">""</span> /> </<span style="color:#f92672">a</span>> <<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">"#add-nav"</span> <span style="color:#a6e22e">title</span><span style="color:#f92672">=</span><span style="color:#e6db74">"Add"</span>> <<span style="color:#f92672">img</span> <span style="color:#a6e22e">src</span><span style="color:#f92672">=</span><span style="color:#e6db74">"/images/icons/ui/add_white_18dp.svg"</span> <span style="color:#a6e22e">alt</span><span style="color:#f92672">=</span><span style="color:#e6db74">""</span> /> </<span style="color:#f92672">a</span>> </code></pre></div><h3 id="css">CSS</h3> <div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-CSS" data-lang="CSS"><span style="color:#f92672">footer</span> <span style="color:#f92672">></span> <span style="color:#f92672">a</span><span style="color:#f92672">[</span><span style="color:#f92672">href</span><span style="color:#f92672">~=</span><span style="color:#e6db74">"#add-nav"</span><span style="color:#f92672">]</span> { <span style="color:#66d9ef">display</span>: <span style="color:#66d9ef">flex</span>; <span style="color:#66d9ef">box-shadow</span>: <span style="color:#66d9ef">none</span>; } <span style="color:#f92672">footer</span> <span style="color:#f92672">></span> <span style="color:#f92672">a</span><span style="color:#f92672">[</span><span style="color:#f92672">href</span><span style="color:#f92672">~=</span><span style="color:#e6db74">"#remove-nav"</span><span style="color:#f92672">]</span> { <span style="color:#66d9ef">display</span>: <span style="color:#66d9ef">flex</span>; } <span style="color:#f92672">footer</span> <span style="color:#f92672">nav</span>:<span style="color:#a6e22e">target</span> <span style="color:#f92672">~</span> <span style="color:#f92672">a</span><span style="color:#f92672">[</span><span style="color:#f92672">href</span><span style="color:#f92672">~=</span><span style="color:#e6db74">"#add-nav"</span><span style="color:#f92672">]</span> { <span style="color:#66d9ef">display</span>: <span style="color:#66d9ef">none</span>; } <span style="color:#f92672">footer</span> <span style="color:#f92672">nav</span> { <span style="color:#66d9ef">display</span>: <span style="color:#66d9ef">none</span>; } <span style="color:#f92672">footer</span> <span style="color:#f92672">nav</span>:<span style="color:#a6e22e">target</span> { <span style="color:#66d9ef">display</span>: <span style="color:#66d9ef">flex</span>; <span style="color:#66d9ef">flex-direction</span>: <span style="color:#66d9ef">column</span>; <span style="color:#66d9ef">position</span>: <span style="color:#66d9ef">fixed</span>; <span style="color:#66d9ef">bottom</span>: <span style="color:#ae81ff">3.5</span><span style="color:#66d9ef">em</span>; <span style="color:#66d9ef">right</span>: <span style="color:#ae81ff">1</span><span style="color:#66d9ef">em</span>; <span style="color:#66d9ef">font-size</span>: <span style="color:#ae81ff">2</span><span style="color:#66d9ef">em</span>; <span style="color:#66d9ef">padding</span>: <span style="color:#ae81ff">0.1</span><span style="color:#66d9ef">em</span> <span style="color:#ae81ff">0.3</span><span style="color:#66d9ef">em</span>; } <span style="color:#f92672">footer</span> <span style="color:#f92672">nav</span>:<span style="color:#a6e22e">target</span> <span style="color:#f92672">a</span> { <span style="color:#66d9ef">display</span>: <span style="color:#66d9ef">flex</span>; <span style="color:#66d9ef">text-shadow</span>: hsla(<span style="color:#ae81ff">218</span>, <span style="color:#ae81ff">20</span><span style="color:#66d9ef">%</span>, <span style="color:#ae81ff">63</span><span style="color:#66d9ef">%</span>, <span style="color:#ae81ff">1</span>) <span style="color:#ae81ff">0</span><span style="color:#66d9ef">px</span> <span style="color:#ae81ff">0</span><span style="color:#66d9ef">px</span> <span style="color:#ae81ff">0</span><span style="color:#66d9ef">px</span>; <span style="color:#66d9ef">text-decoration</span>: <span style="color:#66d9ef">none</span>; <span style="color:#66d9ef">background-color</span>: <span style="color:#66d9ef">white</span>; <span style="color:#66d9ef">color</span>: <span style="color:#66d9ef">transparent</span>; <span style="color:#66d9ef">border-radius</span>: <span style="color:#ae81ff">50</span><span style="color:#66d9ef">%</span>; <span style="color:#66d9ef">box-shadow</span>: <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">5</span><span style="color:#66d9ef">px</span> <span style="color:#ae81ff">5</span><span style="color:#66d9ef">px</span> <span style="color:#ae81ff">-3</span><span style="color:#66d9ef">px</span> rgba(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0.2</span>), <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">8</span><span style="color:#66d9ef">px</span> <span style="color:#ae81ff">10</span><span style="color:#66d9ef">px</span> <span style="color:#ae81ff">1</span><span style="color:#66d9ef">px</span> rgba(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0.14</span>), <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">3</span><span style="color:#66d9ef">px</span> <span style="color:#ae81ff">14</span><span style="color:#66d9ef">px</span> <span style="color:#ae81ff">2</span><span style="color:#66d9ef">px</span> rgba(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0.12</span>); <span style="color:#66d9ef">width</span>: <span style="color:#ae81ff">1.3</span><span style="color:#66d9ef">em</span>; <span style="color:#66d9ef">height</span>: <span style="color:#ae81ff">1.3</span><span style="color:#66d9ef">em</span>; <span style="color:#66d9ef">justify-content</span>: <span style="color:#66d9ef">center</span>; <span style="color:#66d9ef">align-content</span>: <span style="color:#66d9ef">center</span>; <span style="color:#66d9ef">margin-top</span>: <span style="color:#ae81ff">0.5</span><span style="color:#66d9ef">em</span>; <span style="color:#66d9ef">padding</span>: <span style="color:#ae81ff">0.1</span><span style="color:#66d9ef">em</span>; } </code></pre></div><h3 id="how-this-works">How this works</h3> <p>It was fun getting this to work, and it's nice to see that it's just plain HTML and CSS combined with the browsers state.</p> <p>Both anchors are positioned on top of each other, with an initial "add-nav" element positioned visible, and remove-nav hidden.</p> <ol> <li>When the nav element is the target (after the user clicks the add-nav anchor) the menu is displayed (nav:target selectors). We also then hide the "add-nav" anchor and display "remove-nav" anchor.</li> <li>When the user clicks the "remove-nav" anchor there is no matching target element, so the DOM state is reverted and the CSS hides the menu and re-displays the "add-nav" anchor.</li> </ol> <h3 id="trade-offs">Trade offs</h3> <p>It's not without issues, because we are using the browser navigation, each time you click the FAB it will add a navigation to the history stack. On one hand this is good, it means you can dismiss the FAB with a backwards navigation, but on the other hand if you spam the FAB, it will create a lot of navigations. There's no solution without adding JS, I would love a <code>a rel="replace"</code> option on anchors so that we could navigate to an id in the page without creating a history item.</p> <h3 id="conclusion">Conclusion</h3> <p>There are some things that I need to clear up, when the menu opens it would be nice to have some animations, but it was a lot fun creating this and it's great to see how far you can get with just pure HTML and CSS in building rich and interactive applications.</p> <p>If you have any suggestions, please let me know what can be done to improve this.</p> <p>I would also love to see what people can do without layering more and more JS. If you have any other HTML and CSS only UI interactions, then I would love to see them.</p> <p>FAB.</p>


This content originally appeared on Modern Web Development with Chrome and was authored by Paul Kinlan


Print Share Comment Cite Upload Translate Updates
APA

Paul Kinlan | Sciencx (2020-09-23T10:55:20+00:00) FAB without JavaScript. Retrieved from https://www.scien.cx/2020/09/23/fab-without-javascript/

MLA
" » FAB without JavaScript." Paul Kinlan | Sciencx - Wednesday September 23, 2020, https://www.scien.cx/2020/09/23/fab-without-javascript/
HARVARD
Paul Kinlan | Sciencx Wednesday September 23, 2020 » FAB without JavaScript., viewed ,<https://www.scien.cx/2020/09/23/fab-without-javascript/>
VANCOUVER
Paul Kinlan | Sciencx - » FAB without JavaScript. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2020/09/23/fab-without-javascript/
CHICAGO
" » FAB without JavaScript." Paul Kinlan | Sciencx - Accessed . https://www.scien.cx/2020/09/23/fab-without-javascript/
IEEE
" » FAB without JavaScript." Paul Kinlan | Sciencx [Online]. Available: https://www.scien.cx/2020/09/23/fab-without-javascript/. [Accessed: ]
rf:citation
» FAB without JavaScript | Paul Kinlan | Sciencx | https://www.scien.cx/2020/09/23/fab-without-javascript/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.