03 Jan 2021 - tsp
Last update 03 Jan 2021
7 mins
Back in the old days of the world wide web it was common to write fixed layout
pages for the desktop (remember the days of this page is optimized for 600x480 and Internet Explorer
?).
This turned out to be a really bad idea as was already known to professional web
developers but since the web expanded this bad practice swamped the net. As
mobile pages emerged this turned out to be a even worse idea than before and
people started to write additional mobile pages to which they redirected the
browsers based on browser sniffing or some fancy JavaScript based decisions - bad
idea.
The WWW and also HTML is basically designed about some core principles:
The first two parts are addressed by HTML (and also partially CSS). The
hypertext markup language has been designed to allow one to annotate raw text
with semantic information - keep that in mind: HTML itself is not about design,
it’s about semantics. It doesn’t matter if you want to see an emphasis in
italic font or bold - it’s an <em>
. There are only a few HTML tags that
are primarily used for design purposes - <div>
and <span>
which provide
non semantic ways for grouping. All other elements have semantic meaning
that should be kept in mind.
To get back to the topic of this blog post: Since HTML is totally device agnostic
there is no reason to write separate pages for different media or devices. This
inherent and basic property of HTML that existed from day one on is of today
called responsive design and it’s achieved by either choosing sane CSS layout
rules or overriding them in some corner cases using media queries. Media queries
allow one to apply stylesheet rules only on a given subset of output devices
or under given conditions like a specific width (in scalable units). These
are used in CSS following the @
sign (as an example see below). These
rules should be used as seldom as possible - but for some applications where
one really wants different behavior they’re a really nice method to adjust
the page depending on device properties - like for this collapsible menu on
mobile devices.
Why a collapsible menu? Basically the menu bar is usually shown on top of a page. As the page width gets lower and lower the navigation has to reflow into a longer and longer vertical list - and users have to scroll over the navigation every time. It’s a good idea though that users directly see the main content as fast as possible - so the idea is to collapse the navigation as long as the user doesn’t require it. This also fits the behavior people know from their mobile applications anyways. In the early days (before CSS sibling selectors) this has usually been done using JavaScript which is a bad idea for any essential stuff.
Keep in mind that you’re not selecting a specific device though - just resize your browser window on your computer if you’re reading this page on a desktop machine and you’ll see the same effect …
Just as a short recapitulation since they’re not known to the older guys who aren’t as fit with CSS3 - the following combiners are supported in modern CSS:
.classA .classB
selects any object with
the class classB
that’s contained inside an parent element with class classA
.>
) selects only direct children of the given parent,
other than the descendant selector it doesn’t work recursively.+
) selects immediately following siblings
contained under the same parent element. Note that they have to be the
immediate sibling at the same hierarchy level.~
) is extending the adjacent sibling
selector to select all and not only the adjacent siblings that match
the specific conditionIn addition to these selectors (and the optional usage of attribute selectors)
the :checked
pseudo selector is used.
The basic idea is simple: Add a hidden checkbox, an label assigned to that
checkbox (any label that’s assigned to an control triggers it’s clicked even
when being clicked / touched) and use the checked
pseudo-class of the
checkbox to display an sibling div
or ul
/ ol
element. Using
lists also allows a reflowing menu in non-mobile mode (like done on this page
for example)
First one has to build the menu. The most important part is that the part of the menu that will be collapsed and shown/hidden is a sibling of the checkbox, not a child or ancestor. For easier styling I’ll add the whole navigation into a separate division:
<div class="menuToggleBox">
<input type="checkbox" id="mainMenuToggle">
<label for="mainMenuToggle"> Menu </label>
<ul>
<li> <a href="/"> Home </a> </li>
<li> <a href="/example01"> Example 01 </a> </li>
<li> <a href="/example02"> Example 02 </a> </li>
<li> <a href="/example03"> Example 03 </a> </li>
<li> <a href="/example04"> Example 04 </a> </li>
</ul>
<div class="clearfloat"></div>
</div>
Now one can design to go either the mobile-first or the desktop-first route. Since even Google recommends this one should - if one hasn’t any indications from user statistics that desktop users are the majority - take the mobile first approach.
Generally we want to:
On mobile we want to:
/* General */
#mainMenuToggle {
display: none;
}
div.clearfloat {
clear: both;
}
/* Mobile */
div.menuToggleBox label {
display: block;
padding-left: 2.3em;
font-size: 150%;
background: url(/assets/images/png/hamburger.png) no-repeat left center;
}
#mainMenuToggle~ul {
display: none;
}
#mainMenuToggle:checked~ul {
display: block;
}
#mainMenuToggle:checked~label {
background: url(/assets/images/png/closemenu.png) no-repeat left center;
}
div.menuToggleBox ul li {
float: none;
padding: 1ex 1em 1ex 1em;
}
For desktop I’ll use an inverse media query that uses the inverse properties of the targeted mobile solution:
@media not screen or (min-width: 62em) {
div.menuToggleBox label {
display: none;
}
div.menuToggleBox ul {
display: block;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
div.menuToggleBox ul li {
display: block;
float: left;
border-right: 1px solid #FFFFFF;
border-top: 1px solid #FFFFFF;
font-family: monospace;
font-size: 130%;
}
div.menuToggleBox ul li a, div.menuToggleBox ul li a:visited {
color: light-blue;
padding-left: 0.5em;
padding-right: 0.5em;
padding-top: 0.5ex;
padding-bottom: 0.5ex;
}
div.menuToggleBox ul li a:hover {
color: light-red;
font-weight: bold;
padding-left: 0.2em;
padding-right: 0.2em;
padding-top: 0.2ex;
padding-bottom: 0.2ex;
}
}
And since a friend asked how one can implement the transition effects - that’s also rather easy:
div.menuToggleBox ul li a, div.menuToggleBox ul li a:visited {
transition: font-weight 1s,
background-color 1s,
color 1s,
padding-left 1s,
padding-right 1s,
padding-top 1s,
padding-bottom 1s;
}
This article is tagged:
Dipl.-Ing. Thomas Spielauer, Wien (webcomplains389t48957@tspi.at)
This webpage is also available via TOR at http://rh6v563nt2dnxd5h2vhhqkudmyvjaevgiv77c62xflas52d5omtkxuid.onion/