Javascript Tabs Accordion Issue - javascript

I have created a tabs accordion which is working properly. However their behaviour is not as i want it to be. At the current tabs accordion when i press one of the tabs it will show the content inside it, and when i press another tab it will open also. What i would like to have happen is when i click one of the tabs to be the only one that is showing and the rest of the tabs to be closed. Hope someone can help me to add that extra code that i need to make it work.
var tabsContainer = document.getElementById("tabsContainer");
var tabUl = document.getElementById("tabs-ul");
var tabOne = document.getElementById("tab-one");
var tabTwo = document.getElementById("tab-two");
var tabThree = document.getElementById("tab-three");
var tabOneContent = document.getElementById("tab-one-content");
var tabTwoContent = document.getElementById("tab-two-content");
var tabThreeContent = document.getElementById("tab-three-content");
function openTabOne() {
if (tabOneContent.className == "toggleTab") {
tabOneContent.className = "";
} else {
tabOneContent.className = "toggleTab";
}
}
function openTabTwo() {
if (tabTwoContent.className == "toggleTab") {
tabTwoContent.className = "";
} else {
tabTwoContent.className = "toggleTab";
}
}
function openTabThree() {
if (tabThreeContent.className == "toggleTab") {
tabThreeContent.className = "";
} else {
tabThreeContent.className = "toggleTab";
}
}
tabOne.addEventListener("click", openTabOne);
tabTwo.addEventListener("click", openTabTwo);
tabThree.addEventListener("click", openTabThree);
* {
padding: 0px;
margin: 0px;
}
body {
font-family: sans-serif;
font-weight: 14px;
background: silver;
}
#tabsContainer {
width: 50%;
margin: 0 auto;
border: 3px solid #a70d89;
padding: 20px;
box-shadow: 2px 2px 10px rgba(85, 85, 85, 0.77);
;
}
ul {
list-style: none;
}
li {
display: inline-block;
padding: 5px 20px;
background: #4c99ac;
color: #7910c6;
cursor: pointer;
}
#tabsContainer > div {
margin: 20px 0px;
display: none;
}
#tab-one-content.toggleTab,
#tab-two-content.toggleTab,
#tab-three-content.toggleTab {
display: block;
}
<div id="tabsContainer">
<ul id="tabs-ul">
<li id="tab-one">Tab One</li>
<li id="tab-two">Tab Two</li>
<li id="tab-three">Tab Three</li>
</ul>
<div id="tab-one-content">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Placeat quam nesciunt, architecto earum! Beatae explicabo voluptatum rem odit sint dolorem, voluptatem, est iure quia ab voluptates excepturi ratione debitis praesentium.
</div>
<div id="tab-two-content">
Placeat quam nesciunt, architecto earum! Beatae explicabo voluptatum rem odit sint dolorem, voluptatem, est iure quia ab voluptates excepturi ratione debitis praesentium.
</div>
<div id="tab-three-content">
Beatae explicabo voluptatum rem odit sint dolorem, voluptatem, est iure quia ab voluptates excepturi ratione debitis praesentium.
</div>
</div>

You need to remove the class from the tabs that you don't want open anymore, here is a possible way to do it.
var tabsContainer = document.getElementById("tabsContainer");
var tabUl = document.getElementById("tabs-ul");
var tabOne = document.getElementById("tab-one");
var tabTwo = document.getElementById("tab-two");
var tabThree = document.getElementById("tab-three");
var tabPanels = [
document.getElementById("tab-one-content"),
document.getElementById("tab-two-content"),
document.getElementById("tab-three-content")
];
function showTab(tabIndex) {
for(var i = 0; i < tabPanels.length; i++) {
tabPanels[i].className = i == tabIndex ? 'toggleTab' : '';
}
}
function openTabOne() {
showTab(0);
}
function openTabTwo() {
showTab(1);
}
function openTabThree() {
showTab(2);
}
openTabOne();
tabOne.addEventListener("click", openTabOne);
tabTwo.addEventListener("click", openTabTwo);
tabThree.addEventListener("click", openTabThree);
* {
padding:0px;
margin:0px;
}
body {
font-family: sans-serif;
font-weight: 14px;
background:silver;
}
#tabsContainer {
width:50%;
margin:0 auto;
border:3px solid #a70d89;
padding:20px;
box-shadow: 2px 2px 10px rgba(85, 85, 85, 0.77);;
}
ul {
list-style: none;
}
li {
display: inline-block;
padding:5px 20px;
background:#4c99ac;
color:#7910c6;
cursor: pointer;
}
#tabsContainer > div {
margin: 20px 0px;
display: none;
}
#tab-one-content.toggleTab, #tab-two-content.toggleTab, #tab-three-content.toggleTab {
display: block;
}
<div id="tabsContainer">
<ul id="tabs-ul">
<li id="tab-one">Tab One</li>
<li id="tab-two">Tab Two</li>
<li id="tab-three">Tab Three</li>
</ul>
<div id="tab-one-content">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Placeat quam nesciunt, architecto earum! Beatae explicabo voluptatum rem odit sint dolorem, voluptatem, est iure quia ab voluptates excepturi ratione debitis praesentium.
</div>
<div id="tab-two-content">
Placeat quam nesciunt, architecto earum! Beatae explicabo voluptatum rem odit sint dolorem, voluptatem, est iure quia ab voluptates excepturi ratione debitis praesentium.
</div>
<div id="tab-three-content">
Beatae explicabo voluptatum rem odit sint dolorem, voluptatem, est iure quia ab voluptates excepturi ratione debitis praesentium.
</div>
</div>

Related

Why does this Angular Material dialog fail to display both its header and footer?

I have been developing an e-commerce app with Angular 14.
I am currently working on a form that can only ne submitted upon accepting conditions displayed in a modal.
I app.component.ts I have:
import { Component } from '#angular/core';
import { MatDialog, MatDialogConfig } from '#angular/material/dialog';
import { FormGroup, FormControl } from '#angular/forms';
import { HelloComponent } from './hello/hello.component';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
public form: FormGroup = new FormGroup({});
constructor(private dialog: MatDialog) {}
ngOnInit() {
this.form = new FormGroup({
first_name: new FormControl(''),
last_name: new FormControl(''),
phone: new FormControl(''),
email: new FormControl(''),
});
}
public openDialog() {
const dialogConfig = new MatDialogConfig();
// Dialog options
dialogConfig.disableClose = true;
dialogConfig.autoFocus = true;
dialogConfig.width = '420px';
dialogConfig.height = '320px';
this.dialog.open(HelloComponent, dialogConfig);
}
}
In the tenplate, hello.component.html I have
<div mat-dialog-title>
<h2>Terms and Conditions</h2>
</div>
<div mat-dialog-content>
<p>
Quia hic repellendus cupiditate ipsam voluptates, officia reiciendis quas.
Tempore autem quia amet, quas dolor qui animi, quidem neque quam blanditiis
nobis vero temporibus in, nisi dolore adipisci? Minus, cum.
</p>
<p>
Esse placeat nisi iusto earum, eius dolor ipsa aliquam laborum, praesentium
eum, maxime labore maiores odit distinctio! Eius, id amet. Ex quaerat
veritatis suscipit nulla delectus fugit saepe, explicabo eveniet?
</p>
<p>
Optio quae deserunt blanditiis! Quisquam quis libero quae dolor ipsam,
nesciunt dolore alias provident maiores eligendi iusto magnam soluta,
aspernatur exercitationem error temporibus modi neque blanditiis laborum
perspiciatis. Impedit, quis.
</p>
</div>
<mat-dialog-actions>
<button mat-raised-button color="primary" (click)="reject()">Reject</button>
<button mat-raised-button color="primary" (click)="accept()">Accept</button>
</mat-dialog-actions>
The styles:
::ng-deep .mat-dialog-container {
padding: 0 !important;
overflow: hidden;
}
.mat-dialog-content {
padding: 0 10px 0 20px;
margin: 0 -10px;
overflow-y: auto;
overflow-x: hidden;
}
.mat-dialog-title {
margin: 0 !important;
border-bottom: 1px solid #ccc;
}
.mat-dialog-title h2 {
font-size: 18px;
margin: 0;
padding: 10px 0;
text-align: center;
}
p {
font-size: 14px;
line-height: 1.5;
text-align: justify;
margin-top: 0;
margin-bottom: 10px;
}
.mat-dialog-actions {
justify-content: center;
border-top: 1px solid #ccc;
}
The problem
As can be seen in THIS Stackblitz, the dialog's header is not visible (unless its footer, <mat-dialog-actions> is absent).
Questions
How can I fix this bug?
Is there a solution that does not affect the modal's aesthetics?
your title is not shown because your dialog content exceeds the dialogs size.
I also had problems with the sizing in Angular Material dialogs. What I would do is not setting the height in the dialog config (Height in % does not work for whatever reason in MatDialogs).
I'd rather set the height in the mat-dialog-content itself.
I forked your project and made some editing here:
StackBlitz edited
It seems to work like that.
Hope it helps. :)
I have solved it by doing this:
A) Unset the dialog height:
// Dialog options
dialogConfig.disableClose = true;
dialogConfig.autoFocus = true;
dialogConfig.width = '420px';
// dialogConfig.height = '320px';
B) Set the bottom margin of the <mat-dialog-actions> element to 0.
.mat-dialog-actions {
justify-content: center;
border-top: 1px solid #ccc;
margin-bottom: 0;
}

How to apply a class to a div based on div width?

I am trying to add a class to a specific div based on its width, so it is dynamically added or removed as the overall window (and therefore the div, which has a percentage width) resizes.
I've tried using javascript querySelector and offsetWidth to identify the div, but so far it's not working. My method is inspired by this codepen (which gets the window width, so slightly different from what I'm trying to do).
Here's what I have so far:
var addWideClass = function() {
var width = document.querySelector('.v65-productGroup-product').offsetWidth;
if (width < 141) {
$('.v65-productGroup-product').removeClass('wide');
} else if (width >= 415) {
$('.v65-productGroup-product').addClass('wide');
};
};
$(window).resize(function(){
addWideClass();
});
addWideClass();
What do I need to change to have .wide added to .v65-productGroup-product when .v65-productGroup-product > 414px wide?
The offsetWidth may be cashed or have missed a reflow. Browser vendors may choose how to handle DOM calculations like offsetWidth.
As you say: the overall window (and therefore the div, which has a percentage width) resizes. You can change this row to detect window width instead of div width:
var width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || screen.width
Then you can have typical device breakpoints. If you really need it to change when div is 141 and 415 pixels you need to use yor mathematic skills to calculate how wide the window has to be from one of these values added to the rest of widths and procentual factors you know of the neigbouring elements.
maybe this pen helps:
https://codepen.io/anon/pen/zQXMoz
I basically modified the pen you referred to and added the functionality you wanted to. change the page size to see the effect.
P.S. in your own code, did you mean:
if (width < 414) {
instead of
if (width < 141) {
?
additionally, if you just want to toggle the class on 414px, then this should suffice:
if (width < 414) {
// remove class
}
else {
// add class
}
I made this demonstration: See it in full page view and change browser width
"use strict";
console.clear();
const addWideClass = function() {
Array.from(document.getElementsByTagName('span')).forEach(el => {
const w = el.offsetWidth
el.style.setProperty('--w', `'${w}'`);
if (w < 141) {
el.classList.remove("wide");
} else if (w >= 415) {
el.classList.add("wide");
}
})
};
window.addEventListener('resize', addWideClass)
addWideClass()
div {
display: flex;
}
div span {
box-sizing: border-box;
padding: 10px;
--w: '213232';
}
div span:nth-child(1) {
flex-grow: 2;
flex-basis: 0;
background-color: gold;
}
div span:nth-child(2) {
flex-grow: 3;
flex-basis: 0;
background-color: silver;
}
div span:nth-child(3) {
flex-grow: 4;
flex-basis: 0;
background-color: goldenrod;
}
div span.wide {
border: 10px solid #000;
}
div span:before {
content: var(--w);
display: block;
}
<div>
<span>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora similique vitae accusantium repellat nobis architecto unde, exercitationem soluta placeat voluptatum nostrum beatae tenetur ad deleniti voluptate quia quis officia voluptatem.</span>
<span>At ex velit eligendi ipsam doloribus doloremque laudantium, minus mollitia dicta quis sit nostrum commodi incidunt autem provident vero! Rem distinctio, optio harum deserunt aperiam corporis. Quod maxime eos porro!</span>
<span>Quaerat, quo adipisci voluptas dolores odio maxime maiores obcaecati repellendus ducimus a cupiditate placeat, fugiat nostrum distinctio quidem nemo rem error laborum ipsam eos dicta corrupti. Nobis iure suscipit saepe.</span>
</div>
P.S. you might want to consider a debounce on the resize event (I used a second as debounce delay to make the effect more ovious. You would rather want a debounce delay of 100 milliseconds or the like)
"use strict";
console.clear();
const addWideClass = function() {
Array.from(document.getElementsByTagName('span')).forEach(el => {
const w = el.offsetWidth
el.style.setProperty('--w', `'${w}'`);
if (w < 141) {
el.classList.remove("wide");
} else if (w >= 415) {
el.classList.add("wide");
}
})
};
// From: https://davidwalsh.name/javascript-debounce-function
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
window.addEventListener('resize', debounce(addWideClass, 1000))
addWideClass()
div {
display: flex;
}
div span {
box-sizing: border-box;
padding: 10px;
--w: '213232';
}
div span:nth-child(1) {
flex-grow: 2;
flex-basis: 0;
background-color: gold;
}
div span:nth-child(2) {
flex-grow: 3;
flex-basis: 0;
background-color: silver;
}
div span:nth-child(3) {
flex-grow: 4;
flex-basis: 0;
background-color: goldenrod;
}
div span.wide {
border: 10px solid #000;
}
div span:before {
content: var(--w);
display: block;
}
<div>
<span>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora similique vitae accusantium repellat nobis architecto unde, exercitationem soluta placeat voluptatum nostrum beatae tenetur ad deleniti voluptate quia quis officia voluptatem.</span>
<span>At ex velit eligendi ipsam doloribus doloremque laudantium, minus mollitia dicta quis sit nostrum commodi incidunt autem provident vero! Rem distinctio, optio harum deserunt aperiam corporis. Quod maxime eos porro!</span>
<span>Quaerat, quo adipisci voluptas dolores odio maxime maiores obcaecati repellendus ducimus a cupiditate placeat, fugiat nostrum distinctio quidem nemo rem error laborum ipsam eos dicta corrupti. Nobis iure suscipit saepe.</span>
</div>

Is it okay to store an Object on a DOM element in a vanilla JS plugin?

I'm converting jQuery plugins to Vanilla Javascript. I've adopted a Bootstrap-style plugin structure in my example. Once I've instantiated the Accordion object I save it to the dom element so I can later use various methods on the object. Is this an anti-pattern? I would really appreciate any suggestions on how to handle this if it's not correct.
const Accordion = function(element, options){
this.$element = element;
this.target = this.$element.getAttribute('href') || this.$element.dataset.target;
this.$target = document.getElementById(this.target);
this.$header = document.querySelector(`.accordion-header[data-target='${this.target}']`) || document.querySelector(`.accordion-header[href='${this.target}']`);
this.options = {...Accordion.defaults, ...options};
}
Accordion.defaults = {
closeOthers: false
}
Accordion.prototype.open = function(){
this.$header.classList.add('active');
this.$target.classList.add('active');
};
Accordion.prototype.close = function(){
this.$header.classList.remove('active');
this.$target.classList.remove('active');
};
Accordion.prototype.toggle = function(){
if(this.$target.classList.contains('active')){
this.close();
} else {
this.open();
}
};
function Plugin(options){
let accordion = this.Accordion;
if(!accordion){
accordion = new Accordion(this, options);
// Is it okay to store an object on the DOM element?
this.Accordion = accordion;
}
}
const $accordions = [...document.querySelectorAll('[data-toggle="accordion"]')];
const options = {
closeOthers: true
};
/* Call the plugin */
$accordions.forEach($acc => {
Plugin.call($acc, options);
});
$accordions.forEach($acc => {
$acc.addEventListener('click', e => {
e.target.Accordion.toggle();
e.preventDefault();
});
});
const $toggle1 = document.getElementById('toggle1');
const $toggle2 = document.getElementById('toggle2');
const $acc1 = document.getElementById('acc1');
const $acc2 = document.getElementById('acc2');
$toggle1.addEventListener('click', e =>{
$acc1.Accordion.toggle();
});
$toggle2.addEventListener('click', e =>{
$acc2.Accordion.toggle();
});
body {
max-width: 500px;
margin: 0 auto;
padding: 10px;
}
.accordion {
border: 1px solid #ccc;
border-bottom: 0;
margin-bottom: 10px;
}
.accordion-header {
display: block;
padding: 10px;
text-decoration: none;
color: #000;
border-bottom: 1px solid #ccc;
}
.accordion-header.active {
background: #eee;
}
.accordion-body {
padding: 10px;
display: none;
border-bottom: 1px solid #ccc;
}
.accordion-body.active {
display: block;
}
<div class="accordion">
<a id="acc1" href="#1" class="accordion-header" data-toggle="accordion">Header1</a>
<div id="#1" class="accordion-body">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Consequatur aliquid et ipsam cupiditate. Omnis iste quas nostrum aliquid facilis ut natus excepturi deleniti nobis in similique, ex, voluptatibus commodi dolores.
</div>
</div>
<div class="accordion">
<a id="acc2" href="#2" class="accordion-header" data-toggle="accordion">Header2</a>
<div id="#2" class="accordion-body">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Consequatur aliquid et ipsam cupiditate. Omnis iste quas nostrum aliquid facilis ut natus excepturi deleniti nobis in similique, ex, voluptatibus commodi dolores.
</div>
</div>
<button id="toggle1">
Toggle 1
</button>
<button id="toggle2">
Toggle 2
</button>
I wouldn’t worry about it. The only potential problem is name collisions (some other code also tries to assign to element.Accordion and overwrites it). You could also do it with a Map.
var accordions = new Map()
function Accordion ( element ) {
accordions.set( element, this )
}
Accordion.get = element => accordions.get( element )
...
var accordion = Accordion.get( element )

Render only selected element, React JS

I am trying to toggle class in one of my react component.
The idea is to add class when the mouse enter and to remove the class when the mouse leave only in the element only the element in where the user perform the actions. However this is not the case as when the action is being performed all the element with the function are behaving equally.
This is my code so far:
export default class Projects extends Component{
constructor(){
super();
this.state = {
isHovered : false
}
}
//handle mouse enter
handleMouseEnter = () =>{
this.setState({
isHovered : true
});
}
//handle mouse leave
handleMouseLeave = () =>{
this.setState({
isHovered : false
});
}
//render component
render(){
let display = "";
if(this.state.isHovered === true){
display = "active";
}else{
display = "disable";
}
return(
<section className="projects">
{/*section project wrapper*/}
<div className="p-wrapper">
<h1 className="title">Projects</h1>
<hr/>
{/*projet wrapper*/}
<div className="projects-wrapper">
{/*project item wrapper*/}
<div className="project-item" onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>{/*FMA Web development*/}
<div className={"p-description " + display}>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Iure quos dolorem, ipsa eaque minima saepe fugit hic libero recusandae! Obcaecati esse odit id incidunt vitae aperiam dicta atque blanditiis sint?</p>
</div>
<div className="p-image">
<img src="asset/img/fma_web.png" alt="FMA Web Development"/>
</div>
</div>
<div className="project-item" onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>{/*Web development using php*/}
<div className={"p-description " + display}>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Iure quos dolorem, ipsa eaque minima saepe fugit hic libero recusandae! Obcaecati esse odit id incidunt vitae aperiam dicta atque blanditiis sint?</p>
</div>
<div className="p-image">
<img src="asset/img/web_dev_php.png" alt="FMA Web Development Using PHP"/>
</div>
</div>
<div className="project-item" onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>{/*Movie Catalog*/}
<div className={"p-description " + display}>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Iure quos dolorem, ipsa eaque minima saepe fugit hic libero recusandae! Obcaecati esse odit id incidunt vitae aperiam dicta atque blanditiis sint?</p>
</div>
<div className="p-image">
<img src="asset/img/movie_catalog.png" alt="Movie Catalog"/>
</div>
</div>
</div>
</div>
</section>
);
}
}
I have read the use of key in the documentation and read other question especially this one LINK,however when I try to implement I do not get the desired result.
===========================
EDIT
This is what I get now.
As you can see when I hover both of the element triggers.
This is my CSS Code:
/*Projects Start*/
.projects{
width: 100%;
}
.p-wrapper{
margin: 0 auto;
width: 90%;
height: 100%;
}
.projects-wrapper{
margin-top: 2rem;
width: 100%;
display: flex;
justify-content: center;
flex-wrap: wrap;
}
.project-item{
margin: 1rem;
width: 30%;
position: relative;
box-shadow: 2px 3px 37px -5px rgba(0,0,0,0.84);
}
.p-description{
position: absolute;
height: 100%;
width: 100%;
background-color: rgba(43, 40, 40, 0.61);
color: white;
}
.p-description p {
margin: 1rem;
}
.p-title{
margin: 1rem;
}
.active{
display: block;
transition: all 2s ease-in;
}
.disable {
display: none;
}

Dynamic Side Nav Bar

I am a newbie.
I want to build a side navigation bar like available here and here.
As of now, I am able to build a dynamic navigation bar as shown here, though it is not a proper side navigation bar.
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$("document").ready(function(){
$(".menu-button").click(function(){
$(".side-nav-menu").toggle(100);
});
});
</script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-0">
<div>
<a class="btn btn-default menu-button transparent-btn">
<i class="fa fa-bars fa-2x"></i>
<i class=""></i>
</a>
</div>
<div class="side-nav-menu btn-group-vertical" style="display:none">
<button class="btn btn-default transparent-btn btn-lg text-left">About</button>
<button class="btn btn-default transparent-btn btn-lg text-left">Schedule</button>
<button class="btn btn-default transparent-btn btn-lg text-left">Venue</button>
<button class="btn btn-default transparent-btn btn-lg text-left">Speakers</button>
<button class="btn btn-default transparent-btn btn-lg text-left">Contacts</button>
</div>
</div>
</div>
<div>
</body>
I even checked this w3schools website to build the same, but wasn't successful, as explanation is quite difficult.
Can anybody help me out with this?
What if you try this?
.btn-group-vertical {
display: inline-block;
position: absolute;
vertical-align: middle;
z-index: 1;
}
Making the menu positioned absolutely, then adding a z-index so it stays in front.
Its called an off-canvas navigation:
The CSS is:
/* Navigation Menu - Background */
.navigation {
/* critical sizing and position styles */
width: 100%;
height: 100%;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 0;
/* non-critical appearance styles */
list-style: none;
background: #111;
}
/* Navigation Menu - List items */
.nav-item {
/* non-critical appearance styles */
width: 200px;
border-top: 1px solid #111;
border-bottom: 1px solid #000;
}
.nav-item a {
/* non-critical appearance styles */
display: block;
padding: 1em;
background: linear-gradient(135deg, rgba(0,0,0,0) 0%,rgba(0,0,0,0.65) 100%);
color: white;
font-size: 1.2em;
text-decoration: none;
transition: color 0.2s, background 0.5s;
}
.nav-item a:hover {
color: #c74438;
background: linear-gradient(135deg, rgba(0,0,0,0) 0%,rgba(75,20,20,0.65) 100%);
}
/* Site Wrapper - Everything that isn't navigation */
.site-wrap {
/* Critical position and size styles */
min-height: 100%;
min-width: 100%;
background-color: white; /* Needs a background or else the nav will show through */
position: relative;
top: 0;
bottom: 100%;
left: 0;
z-index: 1;
/* non-critical apperance styles */
padding: 4em;
background-image: linear-gradient(135deg, rgb(254,255,255) 0%,rgb(221,241,249) 35%,rgb(160,216,239) 100%);
background-size: 200%;
}
/* Nav Trigger */
.nav-trigger {
/* critical styles - hide the checkbox input */
position: absolute;
clip: rect(0, 0, 0, 0);
}
label[for="nav-trigger"] {
/* critical positioning styles */
position: fixed;
left: 15px; top: 15px;
z-index: 2;
/* non-critical apperance styles */
height: 30px;
width: 30px;
cursor: pointer;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' x='0px' y='0px' width='30px' height='30px' viewBox='0 0 30 30' enable-background='new 0 0 30 30' xml:space='preserve'><rect width='30' height='6'/><rect y='24' width='30' height='6'/><rect y='12' width='30' height='6'/></svg>");
background-size: contain;
}
/* Make the Magic Happen */
.nav-trigger + label, .site-wrap {
transition: left 0.2s;
}
.nav-trigger:checked + label {
left: 215px;
}
.nav-trigger:checked ~ .site-wrap {
left: 200px;
box-shadow: 0 0 5px 5px rgba(0,0,0,0.5);
}
body {
/* Without this, the body has excess horizontal scroll when the menu is open */
overflow-x: hidden;
}
/* Additional non-critical styles */
h1, h3, p {
max-width: 600px;
margin: 0 auto 1em;
}
code {
padding: 2px;
background: #ddd;
}
/* Micro reset */
*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0;}
html, body { height: 100%; width: 100%; font-family: Helvetica, Arial, sans-serif; }
The HTML to be used is:
<ul class="navigation">
<li class="nav-item">Home</li>
<li class="nav-item">Portfolio</li>
<li class="nav-item">About</li>
<li class="nav-item">Blog</li>
<li class="nav-item">Contact</li>
</ul>
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger"></label>
<div class="site-wrap">
<h1>Pure CSS Off-Screen Menu</h1>
<h3>Finally, an off-screen menu that doesn't require a bunch of Javascript to work. </h3>
<p>This concept relies on the <code>:checked</code> pseudo-selector as well as the general sibling <code>~</code> selector, so it has decent browser support.</p>
<p><strong>Browsers supported:</strong> IE9+, Firefox 3.5+, Chrome any, Safari 3.2+, Opera 9.5+</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi vero nisi eos sed qui natus, ut eius reprehenderit error nesciunt veniam aliquam nulla itaque labore obcaecati molestiae eveniet, perferendis provident amet perspiciatis expedita accusantium! Eveniet, quos voluptas et, labore natus, saepe unde est nulla sit eaque tempore debitis accusantium. Recusandae.</p>
<p>Dolorem aliquam a libero reiciendis obcaecati doloribus ipsa eos laudantium, dicta in! Odit iure ut ratione, dolorum cupiditate perferendis voluptatum sapiente, dignissimos sunt necessitatibus, reprehenderit consequatur dolorem. Aliquam veniam quaerat, pariatur deserunt reiciendis vero vitae, repellat omnis sequi dolor nesciunt. Nihil similique alias impedit, obcaecati eligendi delectus voluptatum! Ipsum, vel.</p>
<p>Sint, perspiciatis nemo aut, rerum excepturi deleniti modi quos nihil corporis eum, maiores soluta labore, consectetur eligendi nesciunt. Placeat, incidunt! Illum placeat eligendi, veritatis consectetur eum! Dolor obcaecati minima ab placeat voluptatem neque modi doloribus, magnam qui voluptate eaque in. Nulla expedita hic porro architecto facere officiis vitae numquam, dolor!</p>
<p>Perferendis quis ea incidunt ducimus nisi voluptate natus. Repellat asperiores quod rerum rem quos blanditiis enim modi, veniam voluptas a facilis! Velit cum omnis, voluptatum eum inventore! Corrupti, suscipit, neque distinctio expedita est laboriosam cum aliquid minus tempora quaerat officia possimus unde vel deleniti eaque fugit accusamus iusto dolorum natus.</p>
<p>Demo by Austin Wulf. See article.</p>
</div>
DEMO AVAILABLE ON http://codepen.io/SitePoint/pen/uIemr

Categories

Resources