Blog-Archiv

Mittwoch, 30. Dezember 2015

Pure CSS Push Menu

To finish the intense CSS-blogging of this month, here is a pure CSS push menu.

Restrictions and concepts are the same as with my slide menu, with slight differences that I will explain in the following. This article strongly builds upon that slide-menu Blog, so you might want to read this first.

For smooth scroll behaviour, the demo has been shifted to bottom of this page (click here to see it).

Conceptual Differences to Slide Menu

I 've put the push-menu to left upper corner of the page. Thus it pushes the element to the right of it.

I used the same CSS event-mechanism as in slide-menu, the :focus pseudo-class. Nevertheless the layout had to be done differently, because the push-menu pushes aside page-content, and thus actively takes part in layout, while the slide-menu appears "hover" the page without touching anything.

For pushing, we need to distribute space between the participants, which are the menu and the page-content. Basically we would like to leave the space requirement to the actual text width in the menu, but unfortunately there is no way to express "take preferred size" in CSS. So I have set it to 30 : 70, which means the menu will take 30% of the width when open, while the page-content will keep 70%.

To enable that space distribution, we need to pack the page-content into a wrapping DIV that we can resize when the menu opens. Such was not necessary with the slide-menu.

CSS

If you compare the following CSS to the slide-menu, you will see that parts of it are the same. Different are just pushmenu versus slidemenu classes, and pushmenu-content versus slidemenu-content, and the integration of the page-content class. Of course the CSS state-change treatment also is different, because in a "push" two elements have to be adjusted.

      /* common styles for menu and menu-button */
      .pushmenu {
        position: fixed;
        top: 0; /* be in left upper corner */
        left: 0;
        background-color: lightGray; /* menu would be transparent without background-color */
      }
      /* the open-menu button */
      .menu-button {
        padding: 0.4em;
        margin: 0;
        border: none; /* else border shadow */
      }
      /* initially invisible menu */
      .pushmenu-content {
        width: 0; /* initially invisible */
        height: 0;
        overflow: hidden; /* without this, the menu would be visible even when having zero width */
        transition: 0.5s;
        white-space: nowrap; /* avoids text formatting work during animation */
      }
      /* the content which the menu shares place with */
      .page-content {
        float: right; /* without this, the menu would be a slide-menu, not a push-menu */
        width: 100%; /* initially taking all space, needed due to float right */
        margin-top: 1em; /* leave place for the menu button */
        transition: 0.5s;
        box-sizing: border-box; /* calculate the border as element part */
      }
      /* make menu visible when menu-button is clicked, or mouse is over the menu */
      .menu-button:focus + .pushmenu-content, .pushmenu-content:hover {
        width: 30%; /* take some place when ... */
        height: 100%; /* ... getting visible */
        padding: 1em; /* define padding only when visible! */
        box-sizing: border-box; /* calculate padding as element part */
      }
      /* push page-content when menu-button is clicked, or mouse is over the menu */
      .menu-button:focus ~ .page-content, .pushmenu-content:hover ~ .page-content {
        width: 70%;
        border-left: 0.3em solid transparent; /* when a scrollbar is showing, distance to menu is too small */
      }

Hope the comments were sufficient! When not, here are some further explanations.

The .pushmenu declaration puts the menu into left upper corner.
To use that CSS for push-menus within internal scroll-panes, just change position to absolute, and use scroll-panes like I described in my fixed position Blog.
To put the menu to right side, you would have to change left: 0 to right: 1.3em, and set the float: right property of page-content to left.

Button-styling in .menu-button is exactly the same as in slide-menu.

The .pushmenu-content differs in that it uses width and height instead of max-width and max-height. This is because here we set the width and height to a definite value, we can't use the menu's preferred size as the page-content would not know that value (CSS is too weak for such).

.page-content is the class for the pushed content. It floats to the right, and thus initially must be given 100% width, else it would stick to the right with its preferred size. (I tried to replace the float: right by a relative positioning, but this did not work properly, and most of all it can not be animated).
The margin-top provides space for the menu-button on top.
The border and box-sizing was necessary because there is a sizing issue when a scrollbar is present (page-content was cut on left edge, did not find out the reason).

Finally, the two .menu-button:focus declarations manage the CSS state change, and materialize the push by distributing the space 30 : 70 when the menu-button receives focus.
Mind that the two pushing elements are not in the same layout-layer. The menu is absolute and thus does not take part in normal layout flow, but the static page-content does. Therefore it is not sufficient to size just one of them, both must be sized complementarily.

Mind that both the pushmenu-content and the page-content need the same animation delay, given by transition: 0.5s, for the push to work properly.

HTML

The HTML difference to the slide-menu is just the existence of the content-wrapper with CSS-class page-content. You can also introduce this wrapper into the slide-menu HTML if you like, it won't break it.

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    
    <style type="text/css">
      /* CSS goes here */
    </style>
  </head>
  
  <body>

    <input class="pushmenu menu-button" type="button" value="&#9776;" title="Click to open menu">
    
    <div class="pushmenu pushmenu-content">
      <a href="#one">1 Push Menu</a><br>
      <a href="#two">2 Push Menu</a><br>
      <a href="#three">3 Push Menu</a><br>
      <a href="#four">4 Push Menu</a><br>
    </div>
    
    <div class="page-content">
  
      <h1 id="one">1 Push Menu</h1>
      <p>
        Lore ipsum ...
      </p>
      
      <h1 id="two">2 Push Menu</h1>
      <p>
        Lore ipsum ...
      </p>
            
    </div> <!-- end page-content -->
      
  </body>

</html>

Mind that the HTML elements with CSS classes menu-button and pushmenu-content must be siblings, the first directly preceding the second. The page-content element also must be a sibling of them, but it may follow anywhere behind pushmenu-content (the '~' CSS operator).

Demo

Now here is the demo, nested in an internal scroll-pane.

<- Use this to navigate

1 Push Menu

Lorem ipsum dolor sit amet, qui meliore deserunt at. Percipitur intellegam appellantur cu vim, mei soluta complectitur id, partem reprimique ullamcorper in vim. Eam an porro accusamus dissentiunt, te sit impedit tacimates, movet laboramus mea ad. Putent concludaturque per ei, cu utamur eleifend recteque vel, ancillae suscipit sit no. No qui erat dicunt lucilius. Ullum epicurei ea nec. Elitr laudem eam et, no dicit dissentias sea. Nec an stet decore honestatis, omittam maiestatis ei quo, eripuit facilis recusabo ius cu. Eu oblique detraxit honestatis vim, hinc sonet definitiones has ea. Debet propriae ut his, ne lorem aeque oportere ius, duo autem equidem gloriatur ad. Ei vel illud adolescens. Meis ocurreret ex sit. Ea ferri facer per. Odio gubergren democritum cum ad, ei quaeque philosophia contentiones sit. At atqui choro theophrastus sit, ne erroribus vulputate vis, eam et antiopam scripserit. Et sea altera salutandi iudicabit. Vidisse probatus moderatius cum te, et vis feugiat luptatum consulatu.

2 Push Menu

Lorem ipsum dolor sit amet, qui meliore deserunt at. Percipitur intellegam appellantur cu vim, mei soluta complectitur id, partem reprimique ullamcorper in vim. Eam an porro accusamus dissentiunt, te sit impedit tacimates, movet laboramus mea ad. Putent concludaturque per ei, cu utamur eleifend recteque vel, ancillae suscipit sit no. No qui erat dicunt lucilius. Ullum epicurei ea nec. Elitr laudem eam et, no dicit dissentias sea. Nec an stet decore honestatis, omittam maiestatis ei quo, eripuit facilis recusabo ius cu. Eu oblique detraxit honestatis vim, hinc sonet definitiones has ea. Debet propriae ut his, ne lorem aeque oportere ius, duo autem equidem gloriatur ad. Ei vel illud adolescens. Meis ocurreret ex sit. Ea ferri facer per. Odio gubergren democritum cum ad, ei quaeque philosophia contentiones sit. At atqui choro theophrastus sit, ne erroribus vulputate vis, eam et antiopam scripserit. Et sea altera salutandi iudicabit. Vidisse probatus moderatius cum te, et vis feugiat luptatum consulatu.

3 Push Menu

Lorem ipsum dolor sit amet, qui meliore deserunt at. Percipitur intellegam appellantur cu vim, mei soluta complectitur id, partem reprimique ullamcorper in vim. Eam an porro accusamus dissentiunt, te sit impedit tacimates, movet laboramus mea ad. Putent concludaturque per ei, cu utamur eleifend recteque vel, ancillae suscipit sit no. No qui erat dicunt lucilius. Ullum epicurei ea nec. Elitr laudem eam et, no dicit dissentias sea. Nec an stet decore honestatis, omittam maiestatis ei quo, eripuit facilis recusabo ius cu. Eu oblique detraxit honestatis vim, hinc sonet definitiones has ea. Debet propriae ut his, ne lorem aeque oportere ius, duo autem equidem gloriatur ad. Ei vel illud adolescens. Meis ocurreret ex sit. Ea ferri facer per. Odio gubergren democritum cum ad, ei quaeque philosophia contentiones sit. At atqui choro theophrastus sit, ne erroribus vulputate vis, eam et antiopam scripserit. Et sea altera salutandi iudicabit. Vidisse probatus moderatius cum te, et vis feugiat luptatum consulatu.

4 Push Menu

Lorem ipsum dolor sit amet, qui meliore deserunt at. Percipitur intellegam appellantur cu vim, mei soluta complectitur id, partem reprimique ullamcorper in vim. Eam an porro accusamus dissentiunt, te sit impedit tacimates, movet laboramus mea ad. Putent concludaturque per ei, cu utamur eleifend recteque vel, ancillae suscipit sit no. No qui erat dicunt lucilius. Ullum epicurei ea nec. Elitr laudem eam et, no dicit dissentias sea. Nec an stet decore honestatis, omittam maiestatis ei quo, eripuit facilis recusabo ius cu. Eu oblique detraxit honestatis vim, hinc sonet definitiones has ea. Debet propriae ut his, ne lorem aeque oportere ius, duo autem equidem gloriatur ad. Ei vel illud adolescens. Meis ocurreret ex sit. Ea ferri facer per. Odio gubergren democritum cum ad, ei quaeque philosophia contentiones sit. At atqui choro theophrastus sit, ne erroribus vulputate vis, eam et antiopam scripserit. Et sea altera salutandi iudicabit. Vidisse probatus moderatius cum te, et vis feugiat luptatum consulatu.

For more experiences with pure CSS push-menus you can visit my homepage demo.




Dienstag, 29. Dezember 2015

Replacement for CSS fixed position

The CSS declaration position: fixed pins an HTML element to the browser's view-port. Such an element does not move when you scroll the page content away. But when you apply this CSS to an element that sits within a page-internal scroll-pane, the element would ignore its relative parent and go to top-level, try it out below.

Red button CSS position: absolute fixed

On the right side you find a red menu-button.
It does not scroll with this text, so it is kind of "fixed",
although its CSS position property is set to absolute.
Try to change it to fixed by radio-buttons above.

We learn that position: fixed is good just for the browser's view-port, not for view-ports of page-internal scroll-panes. So when we develop CSS concepts like "sticky header", we always have to change source-code when we want to apply them to elements being in other scroll-containers than the browser itself.

There are voices saying

You shouldn't use internal scroll-panes.
Users do not like to scroll, and it removes accessibility from your web-page.
Besides, it is not printable.

One of the computer application archetypes is the master-details view. Both the master (left) and the details (right) need to be independently scrollable. Think of the JavaDoc page layout, where two left-side frames serve as iterative navigation for a right-side content display. Yes, HTML frames have been deprecated. But: why have they been there? Because they were useful! There will always be situations where you need an internal scroll-pane on a web-page.

There are even more reasons to replace position: fixed than internal scroll-panes. It seems to be not well supported on mobile browsers.

So this article will be about a "fixed" menu button (see my previous Blog) that does not scroll with the page. And it will not use position: fixed, and there will be no JavaScript. Its CSS source-code, with according HTML structure, will be reusable also for buttons that are nested into internal scroll-panes.

How to avoid position: fixed

I would like to distinguish now between

  1. the browser scroll-bar, and
  2. any internal scroll-bar shown by a height-restricted DIV.

To get rid of position: fixed, we need to replace the browser scroll-bar by an internal scroll-bar that should look exactly the same.

The idea is to configure the HTML and BODY tags to be 100% height (I wrote about this in a passed Blog), and then set the BODY to position: relative, so that subsequent elements can be positioned absolute to it. This gives the same effect as position: fixed.

Care must be taken that no position: static content is a direct child of BODY, except just one scroll-pane, which must be configured to height: 100% and overflow: auto (show scrollbar when necessary). The only static content allowed within BODY are elements that have float: left or float: right, and thus do not shift the vertical start-coordinate down.

CSS

Here are the relevant CSS parts (without beautifications like restoring the browser default padding).

Restrict page to the browser's view-port size (avoiding any scrollbars):

      html, body {
        height: 100%;
        width: 100%;
        padding: 0;
        margin: 0;
        overflow: hidden; /* make any eager browser scrollbar disappear */
      }

Define scroll-pane-containers and scroll-panes:

      .scroll-pane-container {
        position: relative;
      }
      .scroll-pane {
        height: 100%;
        width: 100%;
        overflow: auto;
      }

HTML

Here is the necessary HTML structure for this to work.

  <body class="scroll-pane-container">
    
    <div class="scroll-pane">

      <!-- any static content goes here and only here-->

    </div>
    
  </body>

When having long content within that page, you will see a scroll-bar on the right that looks exactly like the browser's scroll-bar, and it also will act the same way. Thus we replaced the browser scroll-bar by an internal scroll-bar of a "ground" DIV.

Sticky Button Example

Here comes an example for the new way to define fixed. We declare sticking to top-right corner by positioning absolutely, and placing the sticky element into the parent element where we want it to stick to.

CSS

      .sticky-top-right {
        position: absolute;
        top: 0;
        right: 1.3em; /* leave place for a scrollbar */
      }

HTML

  <body class="scroll-pane-container">
    
    <input class="sticky-top-right" type="button" value="&#9776;"/>

    <div class="scroll-pane">
        
      <div style="height: 60em;">
        I am the top-level scrolled content.<br>
        Please scroll down to check whether the button moves.
      </div>
      
    </div>

  </body>

Mind that the button is declared where no static content should be: between the scroll-pane-container (BODY) and the scroll-pane. This does not matter because the button is not a static content, its position is absolute.

By the way, you could put the button also inside the scroll-pane. It would make no difference as long as the scroll-pane is not of position: relative.

Compound Example Page

Here is a compound example that shows that the same CSS can drive a top-level sticky button AND a nested sticky button.

I am the top-level scrolled content.
Please scroll down to check whether the button moves, and to see the nested scroll pane.
I am the nested scrolled content.
Please scroll down to check whether the button moves.

The CSS in head contains just the necessary declarations. Irrelevant stylings have been done down in the HTML by inline style attributes.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title>Replace Fixed Position by Absolute</title>
    
    <style type="text/css">
      html, body {
        height: 100%;
        width: 100%;
        padding: 0;
        margin: 0;
        overflow: hidden; /* make any eager browser scrollbar disappear */
      }
      .scroll-pane-container {
        position: relative;
      }
      .scroll-pane {
        height: 100%;
        width: 100%;
        overflow: auto;
      }
      .sticky-top-right {
        position: absolute;
        top: 0;
        right: 1.3em; /* leave place for a scrollbar */
      }
    </style>
  </head>
  
  <body class="scroll-pane-container">
    
    <input class="sticky-top-right" type="button" value="&#9776;"/>

    <div class="scroll-pane">
        
      <div style="height: 60em;">
        I am the top-level scrolled content.<br>
        Please scroll down to check whether the button moves, and to see the nested scroll pane.
      </div>
      
      <div class="scroll-pane-container" style="height: 20em; margin-left: 10%; margin-right: 10%;">
      
        <input class="sticky-top-right" type="button" value="&#9776;"/>
    
        <div class="scroll-pane">
          <div style="height: 30em;">
            I am the nested scrolled content.<br>
            Please scroll down to check whether the button moves.
          </div>
        </div>

      </div>
      
    </div>
    
  </body>
</html>

As you can see here, the definition of scroll-pane-container as CSS class actually made sense. In this example the class is reused in the element-hierarchy of the nested scroll-pane. Mind that all internal scroll-pane-container instances will restrict their height in some way, so it does not make sense to put the height or width definition into the class.

You can see this concept applied to the pure-CSS slide-menu button of my previous Blog on my homepage.




Sonntag, 27. Dezember 2015

Pure CSS Slide Menu

A slide-menu does not move content when it gets visible, like a push-menu does. It appears above the page content, and disappears when the mouse clicks anywhere else. A push-menu pushes aside content when it appears. See here for a demo. Both were invented by "the web". There are no such terms in classical desktop-UI programming, but you could call a slide-menu a popup-menu in desktop-terms.

For smooth scroll behaviour, the demo has been shifted to bottom of this page (click here to see it).

Restrictions

This menu has no sub-menus that can be opened separately by mouse-click. See my past Blog about CSS menus for this problem. But nevertheless it is a simple div that can contain anything.

The normal user experience is that one click opens a menu, and another click closes it again. The pure CSS slide-menu does not behave like that. It stays open until the user clicks anywhere else on the page, and the mouse does not hover it any more. There is no CSS event to catch when the user clicks a second time to the button. Thus the menu covers the button completely when visible, to avoid bad user experience.

On ESCAPE key the menu does NOT disappear.

The menu does not open in a visible area in case the button is on bottom of the page. You would have to scroll upwards then to see the menu-content. A desktop menu would do location-calculations to determine a currently visible area.

Concepts

The basic idea of a slide-menu is to have an on-demand navigation that takes nearly no space on the page. A useful feature would be that it always stays visible, not scrolling with the page content.

A "sandwich" button represents the slide-menu trigger. Its :focus pseudo-class serves for setting the menu-content visible when the user clicks it. Basically this button could be everywhere on the page, but top-right seems to be the best place. Being there, it most likely does not obscure any left-aligned text, and thus it does not need its own layout row, which saves space.

The visibility of the menu-content is not controlled through CSS display, but through setting max-height and max-width, to either zero (invisible), or a very big value the menu (visible) won't ever achieve. There are two reasons for that:

  • we don't want to size any menu individually depending on its content; using max-width is like saying "take your preferred dimension"
  • we like animated UI controls, and display currently can not be animated via CSS

Mind that the max-width way works only for absolutely (or fixed) positioned block elements, because these do not take the whole page width like static block elements do.

CSS

Here is the CSS of the slide-menu, with lots of comments (which I regard to be absolutely necessary for CSS code).

      /* common styles for menu and menu-button */
      .slidemenu {
        position: fixed;
        top: 0;
        right: 1.3em; /* leave place for scrollbar */
        background-color: lightGray;
      }
      /* the open-menu button */
      .menu-button {
        padding: 0.4em;
        border: none; /* else border shadow */
      }
      /* initially invisible menu */
      .slidemenu-content {
        max-height: 0; /* using max-height instead of height avoids a fixed height */
        max-width: 0; /* same for width */
        overflow: hidden;
        transition: 0.5s;
        white-space: nowrap; /* avoids text formatting work during animation */
      }
      /* make menu visible when menu-button is clicked, or mouse is over the menu */
      .menu-button:focus + .slidemenu-content, .slidemenu-content:hover {
        max-height: 60em; /* using max-height instead of height avoids a fixed height */
        max-width: 60em; /* same for width */
        padding: 1em; /* define padding only when being visible! */
        z-index: 1; /* else menu might be covered by some content */
      }

Initially the menu is set to invisible by assigning it max-width: 0 and max-height: 0.

The CSS rule

.menu-button:focus + .slidemenu-content, .slidemenu-content:hover

makes the menu visible. It applies when the user clicks the button, and stays active as long as the mouse does not click elsewhere on the page. The :hover rule avoids the menu closing in case the mouse clicks on it, because then the button loses focus. Precondition for this to work is that the menu-button HTML-element is directly followed by the menu-content HTML-element, as sibling (described by the CSS '+' operator).

The menu-content needs a z-index when visible, else it might be covered by page contents.

The transition: 0.5s says that all changes should be done animated within half a second. This is all you have to do for a menu animation, elegantly via CSS.

Mind that you need to define some background-color for the menu-content, else it will be transparent. But the .menu-button styles and the .slidemenu-content padding are not relevant for the functionality.

HTML

Here is the necessary HTML structure.

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1"/>

    <style type="text/css">
      /* CSS goes here */
    </style>
  </head>
  
  <body>

    <input class="slidemenu menu-button" type="button" value="&#9776;" title="Click to open menu">
    
    <div class="slidemenu slidemenu-content">
      <p><a href="#one">1 Slide Menu</a></p>
      <p><a href="#two">2 Slide Menu</a></p>
      ....
    </div>
      
    <h4 id="one">1 Slide Menu</h4>
    <p>
      Lore ipsum ...
    </p>

    <h4 id="two">2 Slide Menu</h4>
    <p>
      Lore ipsum ...
    </p>
    ....

  </body>
</html>

Important is that the menu-button must be the direct predecessor sibling of the menu-content. It is not important how the link target elements are organized.

Demo

The following demo shows a slide-menu button that won't scroll with the content.

This example is nested into a web-page. The concept of a CSS slide-menu is easier to explain with a top-level menu using CSS position: fixed. Thus the CSS working here differs slightly from the source discussed in this article, in that it has a relative parent and is positioned absolutely. The migration between these models can be done with changing just a few CSS lines:

      .slidemenu {
        position: absolute;
        ....
      }

But mind that for this to work you need a scroll-pane and a scroll-pane-container above the button. I will explain this soon in another Blog.

A problem occurs when the wrapping page is longer than this example, meaning there is more page content below. Then the browser moves the chosen chapter to the top of its view-port, which is not user-friendly, but currently I do not know a workaround for that (by the way, this is not related to a slide-menu).

Use this to navigate ->

1 Slide Menu

Lorem ipsum dolor sit amet, qui meliore deserunt at. Percipitur intellegam appellantur cu vim, mei soluta complectitur id, partem reprimique ullamcorper in vim. Eam an porro accusamus dissentiunt, te sit impedit tacimates, movet laboramus mea ad. Putent concludaturque per ei, cu utamur eleifend recteque vel, ancillae suscipit sit no. No qui erat dicunt lucilius. Ullum epicurei ea nec. Elitr laudem eam et, no dicit dissentias sea. Nec an stet decore honestatis, omittam maiestatis ei quo, eripuit facilis recusabo ius cu. Eu oblique detraxit honestatis vim, hinc sonet definitiones has ea. Debet propriae ut his, ne lorem aeque oportere ius, duo autem equidem gloriatur ad. Ei vel illud adolescens. Meis ocurreret ex sit. Ea ferri facer per. Odio gubergren democritum cum ad, ei quaeque philosophia contentiones sit. At atqui choro theophrastus sit, ne erroribus vulputate vis, eam et antiopam scripserit. Et sea altera salutandi iudicabit. Vidisse probatus moderatius cum te, et vis feugiat luptatum consulatu.

2 Slide Menu

Lorem ipsum dolor sit amet, qui meliore deserunt at. Percipitur intellegam appellantur cu vim, mei soluta complectitur id, partem reprimique ullamcorper in vim. Eam an porro accusamus dissentiunt, te sit impedit tacimates, movet laboramus mea ad. Putent concludaturque per ei, cu utamur eleifend recteque vel, ancillae suscipit sit no. No qui erat dicunt lucilius. Ullum epicurei ea nec. Elitr laudem eam et, no dicit dissentias sea. Nec an stet decore honestatis, omittam maiestatis ei quo, eripuit facilis recusabo ius cu. Eu oblique detraxit honestatis vim, hinc sonet definitiones has ea. Debet propriae ut his, ne lorem aeque oportere ius, duo autem equidem gloriatur ad. Ei vel illud adolescens. Meis ocurreret ex sit. Ea ferri facer per. Odio gubergren democritum cum ad, ei quaeque philosophia contentiones sit. At atqui choro theophrastus sit, ne erroribus vulputate vis, eam et antiopam scripserit. Et sea altera salutandi iudicabit. Vidisse probatus moderatius cum te, et vis feugiat luptatum consulatu.

3 Slide Menu

Lorem ipsum dolor sit amet, qui meliore deserunt at. Percipitur intellegam appellantur cu vim, mei soluta complectitur id, partem reprimique ullamcorper in vim. Eam an porro accusamus dissentiunt, te sit impedit tacimates, movet laboramus mea ad. Putent concludaturque per ei, cu utamur eleifend recteque vel, ancillae suscipit sit no. No qui erat dicunt lucilius. Ullum epicurei ea nec. Elitr laudem eam et, no dicit dissentias sea. Nec an stet decore honestatis, omittam maiestatis ei quo, eripuit facilis recusabo ius cu. Eu oblique detraxit honestatis vim, hinc sonet definitiones has ea. Debet propriae ut his, ne lorem aeque oportere ius, duo autem equidem gloriatur ad. Ei vel illud adolescens. Meis ocurreret ex sit. Ea ferri facer per. Odio gubergren democritum cum ad, ei quaeque philosophia contentiones sit. At atqui choro theophrastus sit, ne erroribus vulputate vis, eam et antiopam scripserit. Et sea altera salutandi iudicabit. Vidisse probatus moderatius cum te, et vis feugiat luptatum consulatu.

4 Slide Menu

Lorem ipsum dolor sit amet, qui meliore deserunt at. Percipitur intellegam appellantur cu vim, mei soluta complectitur id, partem reprimique ullamcorper in vim. Eam an porro accusamus dissentiunt, te sit impedit tacimates, movet laboramus mea ad. Putent concludaturque per ei, cu utamur eleifend recteque vel, ancillae suscipit sit no. No qui erat dicunt lucilius. Ullum epicurei ea nec. Elitr laudem eam et, no dicit dissentias sea. Nec an stet decore honestatis, omittam maiestatis ei quo, eripuit facilis recusabo ius cu. Eu oblique detraxit honestatis vim, hinc sonet definitiones has ea. Debet propriae ut his, ne lorem aeque oportere ius, duo autem equidem gloriatur ad. Ei vel illud adolescens. Meis ocurreret ex sit. Ea ferri facer per. Odio gubergren democritum cum ad, ei quaeque philosophia contentiones sit. At atqui choro theophrastus sit, ne erroribus vulputate vis, eam et antiopam scripserit. Et sea altera salutandi iudicabit. Vidisse probatus moderatius cum te, et vis feugiat luptatum consulatu.

For more experience with pure CSS slide-menus you can visit my homepage demo.


Samstag, 26. Dezember 2015

Protruding CSS inline elements

This article is about a SPAN element that destroyed my layout, and it took me quite a time to find the explanation for that.

You may know about the fact that there are inline and block elements in HTML, see this page for quick information, and this page for a compound tutorial. In short:

  • inline elements (like SPAN) flow horizontally, like text, next to each other
  • block elements (like DIV) flow vertically, they start a new line and cover the whole width

It is illegal to put a block element inside an inline element, so a DIV inside a SPAN is not legal HTML. Although browsers may accept it, they could interpret it differently.

Now there are some side effects when using inline elements. I came across one of them when using a SPAN with some padding and border. Look at the example below:

Parent
Child 1
Child 2

!

The Child 2 SPAN obviously protrudes from its Parent DIV. And it also covers parts of its adjacent Child 1 DIV.

!

Here is the HTML:

  <div id="parent" style="border: 1px solid red; background-color: cyan; margin-left: 20%; margin-right: 20%;">
  Parent
  
    <div id="child1" style="border: 0.5em solid green; background-color: yellow;">
    Child 1
    </div>
    
    <span id="child2" style="border: 1em solid blue; background-color: orange;">
    Child 2
    </span>
    
  </div>

This happens just

  • on top and bottom of the element, not left or right of it
  • when there is a padding, or a border, or both
  • with inline elements like SPAN

So why is this happening, and how to fix this?
If you want to try a fix, here is a playground. For the distrustful among you I also added the box-sizing property, but actually it does not play any role here.

Child 1 DIV
display:
padding:
em
border:
em
margin:
em
Child 2 SPAN
display:
padding:
em
border:
em
margin:
em
box-sizing:


Parent
Child 1
Child 2


Unfortunately not even the CSS21 specification gave me a clear answer to this problem. I found it here. Solution is (also on stackoverflow):

Inline elements:
  • respect left and right margin / padding / border, but not top and bottom
  • cannot have a width and height

So try to set the display: inline property of the Child 2 SPAN in the playground above to inline-block. You will see that the problem is fixed then.

Here is the fixed HTML:

  <div id="parent" style="border: 1px solid red; background-color: cyan; margin-left: 20%; margin-right: 20%;">
  Parent
  
    <div id="child1" style="border: 0.5em solid green; background-color: yellow;">
    Child 1
    </div>
    
    <span id="child2" style="border: 1em solid blue; background-color: orange; display: inline-block;">
    Child 2
    </span>
    
  </div>

So always put display: inline-block; upon any SPAN that has a border or padding, else it might protrude from its parent, and obscure sibling elements.




Samstag, 19. Dezember 2015

Receiving CSS Events

"Event" is a quite diffuse term. It is something that happens unpredictably, we need to "listen" (wait) for it when we want to act on it. For example, operating systems generate events when you use mouse or keyboard.

Disambiguation: in the Java world, events also could be understood as a method-call on 0-n objects that implement a certain listener-interface and have registered for being notified. This is an event abstraction, used to implement loosely coupled parts of an application. The event dispatching mechanism then could be replaced by e.g. network communication at a later time.

Web-pages send events to JavaScript listeners that have registered themselves by calling browserObject.addEventListener(eventType, listenerFunction), for example

window.addEventListener('scroll', function(event) { console.log('scroll event '+event); });

But we can not register CSS event listeners. Can we?

CSS Rule-Sets Targeting State Changes

You may have seen "Pure CSS" solutions. These actually react upon user input events and alter the page accordingly, for example by opening a menu. And there is no JavaScript in that page that does this! So how does this work?

The idea is to define a CSS-rule that is fulfilled sometimes when a certain state is obtained. For example, when the mouse hovers a certain element (= state), we want to make its font bold. We can detect state changes using CSS pseudo-classes. These are the trailing optional :xxx expressions in CSS selectors (not to be confused with pseudo-elements, which are ::xxx).

Following page defines different colours for active, focus, hover, target pseudo-classes. Paste the page into some file and view it by using the file:/// protocol in the browser address line. Move the mouse in and out the page, over elements, click on elements, and watch how pseudo-classes change the page.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title>Pseudo Classes Test</title>
    
    <style type="text/css">
      :active {
        color: green;
      }
      :focus {
        border: 2px solid red;
      }
      :hover {
        background-color: lightGray;
      }
      :target {
        outline: 2px solid blue;
      }
    </style>
  </head>
  
  <body>
    
    <p>Non-focusable element: p</p>
    
    <div>Non-focusable element: div</div>
    
    <button>HTML Button &#9776;</button>
      
    <input type="button" value="Native Input Button &#9776;" />
    
    <a href="#linkTarget">Hyperlink anchor</a>
    <p id="linkTarget">This is the link's target</p>
    
  </body>

</html>

You can find a list of pseudo classes at many places on the internet. Really useful for animating web pages are only few:

  • :focus ... becomes true when a focusable element is clicked
  • :target ... becomes true when a hyperlink pointing to an internal target is clicked

But even these leak:

  1. The :focus pseudo-class actually gives you a mouse click for input-elements like a button. You can then open a menu. But when the user again clicks to the button, you can not close the menu through CSS. Just a click elsewhere on the page will release the :focus state. Finding out this is unfortunately up to the user.

  2. To be able to use :target, you need to define hyperlinks. The browser would scroll down to the link's internal target element as soon as it was clicked, which may not be what you intended.

  3. When you use :target, the internal link-target will appear in the browser address line, and the browser's "Back" button then would not do what the user expects.

Pure CSS solutions mostly need getting used to, which is not an option in our world of increasing comfort. I do not know your usability preferences, but hover-menus are definitely not what I consider to be ergonomic, they are too intrusive.

CSS State Change Receipt Examples

1. :focus Popup

Catching a click on a button provides the opportunity to make an element visible that was invisible before. Mind that only few HTML elements are initially focusable: input, select, button, textarea, iframe, a ("anchor", the hyperlink element). But you can make any element focusable by adding the tabindex attribute with a value >= 0 to it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    
    <style type="text/css">
      .focusPopup {
        max-height: 0;
        max-width: 0;
        overflow: hidden; /* else would be visible despite zero height/width */
      }
      .focusTrigger:focus + .focusPopup, .focusPopup:hover {
        max-height: 120em;
        max-width: 120em;
        background-color: lightGray;
      }
    </style>
    
  </head>
  
  <body>
      
    <div>
      <input class="focusTrigger" type="button" value="&#9776;" title="Click me!">
      
      <div class="focusPopup">
        <p>Focus One</p>
        <p>Focus Two</p>
        <p>Focus Three</p>
      </div>
    </div>
    
  </body>
 
</html>


Source code explanations:

Any input class="focusTrigger" are focusable elements we install our pseudo-class listener on. Initially we set any focusPopup to invisible by defining their max-width / max-height as zero.

The CSS rule .focusTrigger:focus + .focusPopup describes the direct follower element (sibling) of the focusTrigger in case the button has received the user input focus (mouse click). So when the pseudo-class becomes true, this rule changes the max-width / max-height properties of the focusPopup to make it visible.

Additionally we do not want to close the focusPopup when it receives a click, because its focusTrigger would lose the :focus pseudo-class then. So I also defined a rule that does the same as .focusTrigger:focus + .focusPopup, but becomes true on mouse-hovering the focusPopup. This results in the CSS alternative .focusTrigger:focus + .focusPopup, .focusPopup:hover.

I used max-width / max-height instead of width / height to avoid a fixed size for the focusPopup. I haven't tested this on all browsers, but this seems to make the content take its "preferred size". Originally this menu was created as slide-menu, being fixed on browser viewport, hovering the page content. When using this as push-menu, you could also use display: none; and display: block; instead of max-width / max-height. But mind that the display can not be animated by e.g. transition: 1s;, animation you could achieve only with some size-property.

Mind that this solution won't work when the focusPopup is not the direct follower of focusTrigger!

2. :target Tabs

This example shows how tabs can be implemented without JavaScript. But mind that clicking on an internal link

  1. will put a bookmark into the browser address line and thus add to browser history
  2. will scroll down to the target of the link when the page is scrollable

Further you can not make the first tab initially visible.
So you may find this solution to be not so useful. Anyway, here is the example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    
    <style type="text/css">
      .linkedTab {
        display: none;
      }
      .linkedTab:target { /* mind that the page will move to the start of the clicked link when it is scrollable! */
        display: block;
      }
    </style>
    
  </head>
  
  <body>
      
    <div>
    
      <a href="#linkedTab1" title="Click me!">Tab-1</a>
      <a href="#linkedTab2" title="Click me!">Tab-2</a>
      <a href="#linkedTab3" title="Click me!">Tab-3</a>
      
      <div id="linkedTab1" class="linkedTab">
        <p>One</p>
      </div>
      
      <div id="linkedTab2" class="linkedTab">
        <p>Two</p>
      </div>
      
      <div id="linkedTab3" class="linkedTab">
        <p>Three</p>
      </div>
      
    </div>
    
  </body>

</html>


Source code explanations:

There are three hyperlinks on the page. Each points to a different internal target HTML-id: a href="#linkedTab1". The target itself is the tab, given as element with that HTML-id. All of them are initially invisible by the rule .linkedTab.

When the user clicks on a hyperlink, the CSS pseudo-class :target becomes active on the target element (which is the tab). Then the rule .linkedTab:target applies and sets the tab visible. The rule .linkedTab:target is stronger than .linkedTab because it has a higher specifity.

Conclusion

Pure CSS solutions are not really user-friendly. CSS is more for colors, fonts, borders, and maybe also for layout. Building menus or tabs on CSS always leaks somehow (which does not mean that we shouldn't use pseudo-classes).