Initial import
authorAntonio Ospite <ao2@ao2.it>
Thu, 29 Jun 2017 14:28:50 +0000 (16:28 +0200)
committerAntonio Ospite <ao2@ao2.it>
Thu, 29 Jun 2017 14:28:50 +0000 (16:28 +0200)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
index.html [new file with mode: 0644]
scss/_modules.scss [new file with mode: 0644]
scss/modules/_font-icons.scss [new file with mode: 0644]
scss/modules/_toggle-menu.scss [new file with mode: 0644]
scss/style.scss [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..32bf1bc
--- /dev/null
@@ -0,0 +1,2 @@
+.sass-cache/
+css/
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..0bd2c7a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+SCSS_SOURCE_DIR := scss
+SCSS_SOURCES   := $(wildcard $(SCSS_SOURCE_DIR)/[^_]*.scss)
+
+CSS_DEST_DIR := css
+CSS_COMPILED := $(SCSS_SOURCES:$(SCSS_SOURCE_DIR)/%.scss=%.css)
+
+SCSS_OUTPUT_TYPE := expanded
+
+SCSS_BIN := sassc
+SCSS_FLAGS := -t $(SCSS_OUTPUT_TYPE)
+
+update: $(CSS_COMPILED)
+
+clean:
+       rm -rf $(CSS_DEST_DIR) .sass-cache
+
+%.css: $(SCSS_SOURCE_DIR)/%.scss
+       @[ -d $(CSS_DEST_DIR) ] || mkdir -p $(CSS_DEST_DIR)
+       $(SCSS_BIN) $(SCSS_FLAGS) $< $(CSS_DEST_DIR)/$@
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..4150448
--- /dev/null
+++ b/README
@@ -0,0 +1,40 @@
+An SCSS mixin for pure CSS responsive toggle menus without hacks.
+
+The selectors name follows the BEM scheme, the file structure follows SMACSS.
+
+Inspired by:
+  - http://bradfrost.com/blog/web/responsive-nav-patterns/
+  - http://www.creativebloq.com/css3/build-smart-mobile-navigation-without-hacks-6122800
+  - https://gist.github.com/joesnellpdx/4151902
+  - https://codepen.io/joesnellpdx/pen/ktGdx
+
+
+Dependencies:
+  - sassc or ruby-sass
+
+
+Demo:
+  1. Install 'sassc', on Debian systems:
+    $ sudo apt-get install sassc
+  2. Download this code.
+  3. Run 'make' to build the final css style.
+  4. Load the page:
+    $ xdg-open index.html
+
+
+How it works
+============
+
+In HTML, linking to an element using its fragment id allows to pass some state
+info to the page via the URL and then capture it in the CSS :target selector.
+
+Moreover HTML specifies the behavior of scrolling when navigating to
+a fragment id, in particular the specification says: "if the destination is
+not being rendered the User Agent must do nothing", see also
+https://www.w3.org/TR/html5/single-page.html#scroll-to-fragid
+
+So, according to the specification linking to an hidden element using its
+fragment id does not cause any scrolling.
+
+This behavior is to use a simple link as a mechanism to set the states of the
+menu (show, hide) and style them in CSS.
diff --git a/index.html b/index.html
new file mode 100644 (file)
index 0000000..d098b89
--- /dev/null
@@ -0,0 +1,67 @@
+<!doctype html>
+
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+
+  <title>Toggle Navigation: No JS</title>
+  <meta name="description" content="Toggle Navigation: No JS">
+  <meta name="author" content="Antonio Ospite">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+  <link rel="stylesheet" href="css/style.css">
+</head>
+
+<body>
+  
+  <header role="banner" class="pattern">
+    <h1>Toggle Navigation: No JS</h1>
+  </header>
+
+  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+
+  <nav class="toggle-menu" role="navigation">
+    <!--
+      The toggle-menu__target elements will be hidden to avoid scrolling around
+      when navigating to the fragment ids, see also
+      https://www.w3.org/TR/html5/single-page.html#scroll-to-fragid
+    -->
+    <div id="show-nav-menu" class="toggle-menu__target"></div>
+    <div id="hide-menu" class="toggle-menu__target"></div>
+
+    <a class="toggle-menu__button toggle-menu__button--show" href="#show-nav-menu">Show Menu</a>
+    <a class="toggle-menu__button toggle-menu__button--hide" href="#hide-menu">Hide Menu</a>
+    <ul class="toggle-menu__list" tabindex="0">
+      <li class="toggle-menu__item"><a href="#">Home</a></li>
+      <li class="toggle-menu__item"><a href="#">About</a></li>
+      <li class="toggle-menu__item"><a href="#">Products</a></li>
+      <li class="toggle-menu__item"><a href="#">Services</a></li>
+      <li class="toggle-menu__item"><a href="#">Contact</a></li>
+    </ul>
+  </nav>
+
+  <p><strong>Another Menu</strong></p>
+
+  <nav class="toggle-menu">
+    <div id="show-nav-menu-2" class="toggle-menu__target"></div>
+
+    <a class="toggle-menu__button toggle-menu__button--show" href="#show-nav-menu-2">Show Menu 2</a>
+    <a class="toggle-menu__button toggle-menu__button--hide" href="#hide-menu">Hide Menu 2</a>
+    <ul class="toggle-menu__list" tabindex="0">
+      <li class="toggle-menu__item"><a href="#">Feeds</a></li>
+      <li class="toggle-menu__item"><a href="#">Social</a></li>
+    </ul>
+  </nav>
+
+  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+
+  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+
+  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+
+  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+
+  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+
+</body>
+</html>
diff --git a/scss/_modules.scss b/scss/_modules.scss
new file mode 100644 (file)
index 0000000..db3ba12
--- /dev/null
@@ -0,0 +1,2 @@
+@import "modules/_toggle-menu";
+@import "modules/_font-icons";
diff --git a/scss/modules/_font-icons.scss b/scss/modules/_font-icons.scss
new file mode 100644 (file)
index 0000000..c6cf78a
--- /dev/null
@@ -0,0 +1,11 @@
+// Inspired by http://jaydenseric.com/blog/fun-with-sass-and-font-icons
+// To be more portable a well defined font-family should be used for icons.
+
+@function icon($icon) {
+  $icons: (
+    cross: "\2715",
+    hamburger: "\2630",
+  );
+
+  @return map-get($icons, $icon);
+}
diff --git a/scss/modules/_toggle-menu.scss b/scss/modules/_toggle-menu.scss
new file mode 100644 (file)
index 0000000..1cb6f4d
--- /dev/null
@@ -0,0 +1,174 @@
+// toggle-menu - An SCSS mixin for pure CSS responsive toggle menus
+// 
+// Copyright (C) 2017  Antonio Ospite <ao2@ao2.it>
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+@mixin _toggle-menu-common($show-menu-id) {
+
+  /* common fallback style for when :target is not supported */
+  .toggle-menu {
+    .toggle-menu__target {
+      display: none;
+    }
+
+    .toggle-menu__button--show {
+      display: none;
+    }
+
+    .toggle-menu__button--hide {
+      display: none;
+    }
+
+    .toggle-menu__list .toggle-menu__item {
+      height: auto;
+    }
+  }
+
+  /* common mobile-first style for when :taget is supported */
+  body:not(:target) .toggle-menu {
+    .toggle-menu__list .toggle-menu__item {
+      overflow: hidden;
+      height: 0;
+    }
+
+    .toggle-menu__button--show {
+      display: block;
+    }
+
+    .toggle-menu__button--hide {
+      display: none;
+    }
+  }
+
+  @media screen and (min-width: 48.25em) {
+    body:not(:target) .toggle-menu {
+      .toggle-menu__list .toggle-menu__item {
+        display: inline-block;
+        overflow: inherit;
+      }
+    }
+  }
+}
+
+@mixin _toggle-menu-theme {
+
+  .toggle-menu {
+
+    a {
+      color: white;
+      text-decoration: none;
+    }
+
+    .toggle-menu__button {
+      cursor: pointer;
+      line-height: 2em;
+      padding: .5em;
+      font-weight: bold;
+
+      &:after {
+        content: icon(hamburger);
+        font-size: 2em;
+        float: right;
+      }
+    }
+
+    .toggle-menu__button--show {
+      background-color: red;
+    }
+
+    .toggle-menu__button--hide {
+      background-color: darkred;
+      &:after {
+        content: icon(cross);
+      }
+    }
+
+    .toggle-menu__list {
+      background-color: orange;
+      list-style-type: none;
+      margin-top: 0;
+      padding: 0;
+    }
+
+    .toggle-menu__list .toggle-menu__item {
+      a {
+        color: black;
+        padding: .5em 1em;
+        display: block;
+
+      }
+      :hover {
+        background-color: yellow;
+      }
+    }
+  }
+}
+
+
+$imported-once: false !default;
+@mixin toggle-menu-common($show-menu-id) {
+  $imported-once: $imported-once !global;
+  @if ($imported-once == false) {
+    $imported-once: true !global;
+    @include _toggle-menu-common($show-menu-id);
+    @include _toggle-menu-theme;
+  }
+}
+
+@mixin toggle-menu($show-menu-id) {
+
+  @include toggle-menu-common($show-menu-id);
+
+  /* mobile-first style for ##{$show-menu-id} when :target is supported */
+  body:not(:target) .toggle-menu {
+    ##{$show-menu-id}:target {
+      ~ .toggle-menu__list .toggle-menu__item {
+        height: auto;
+        -moz-transition: height .25s, line-height .25s;
+        -ms-transition: height .25s, line-height .25s;
+        -o-transition: height .25s, line-height .25s;
+        -webkit-transition: height .25s, line-height .25s;
+        transition: height .25s, line-height .25s;
+      }
+
+      ~ .toggle-menu__button--show {
+        display: none;
+      }
+
+      ~ .toggle-menu__button--hide {
+        display: block;
+      }
+    }
+  }
+
+  /* big screen style for ##{$show-menu-id} when :target is supported */
+  @media screen and (min-width: 48.25em) {
+    body:not(:target) .toggle-menu {
+      ##{$show-menu-id}, ##{$show-menu-id}:target {
+        ~ .toggle-menu__list .toggle-menu__item {
+          height: auto;
+        }
+
+        ~ .toggle-menu__button--show {
+          display: none;
+        }
+
+        ~ .toggle-menu__button--hide {
+          display: none;
+        }
+      }
+    }
+  }
+}
diff --git a/scss/style.scss b/scss/style.scss
new file mode 100644 (file)
index 0000000..4994fb6
--- /dev/null
@@ -0,0 +1,6 @@
+@charset 'utf-8';
+
+@import "_modules";
+
+@include toggle-menu("show-nav-menu");
+@include toggle-menu("show-nav-menu-2");