Show Div on Nav Element Click and Hide Other Divs - javascript

I built a navbar in HTML and also some Divs which are populated with a bunch of content that pertains to each nav element.
What I want to do is show the div which pertains to the selected nav element when it is clicked and hide the other divs that pertain to the other nav elements.
Basically what needs to happen is when a user clicks on a Nav Item, the class for that nav item needs to be set to 'navItem active on' in the html. Not sure if this is something that happens automatically or not.
After that, the display property defined in the CSS for the content panel of that nav item needs to be changed to 'block' and all other content panels should then have their 'display' property changed to 'none' so that they are not displayed in the page.
In the example given, I only have two content panels defined in the CSS and HTML (Capabilities and Tutorials), but each navItem will receive it's own content panel which should be toggled on when it is clicked.
I really have no idea where to begin with this. I'm pretty sure this requires JavaScript but this is literally my first attempt at building a web page and it took me 2 days even after copying a lot from another website I used for inspiration. Any help, guidance or insight is greatly appreciated.
CSS + HTML:
var links = document.getElementsByClassName("navItem");
for (i = 0; i < links.length; i++) {
var link = links[i];
link.addEventListener('click',function(sender, event) {
event.preventDefault();
/* hide all panels */
var panels = document.getElementsByClassName("panel");
for (j = 0; j < panels.length; j++) {
panels[j].style.display = 'none';
}
/* Show the selected panel */
var panel_id = sender.target.getAttribute("panel-id");
document.getElementById(panel_id).style.display = 'block';
}
}
/* FONT ASSIGNMENTS
--------------------------- */
/* General Use */
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
p,
small {
font-family: 'Avenir LT W01 35 Light', Arial, Helvetica, sans-serif;
}
p.large-text {
font-size: 18px !important;
}
hr {
background-color: #e0e0e0;
color: #e0e0e0;
}
.center-content {
text-align: center !important;
}
/* Special Use */
h1,
h2,
h1 a,
h2 a,
h3,
h3 a,
infoBar,
.gisFont1,
.gisFont1 a {
font-weight: normal !important;
font-style: normal;
line-height: normal;
font-variant: normal;
font-family: 'Avenir LT W01 35 Light', Arial, Helvetica, sans-serif;
}
/*-- END FONT ASSIGNMENTS --*/
/* INFOBAR - The Infobar is the navigation element at the top
used to navigate the subpages of the document and change the content
panel's content depending on the selected infoBar navigation element
--------------------------- */
/* infoBar Bottom Border */
#infoBar {
background: #FFF;
/*border-top: 1px solid #e5e5e5;*/
border-bottom: 1px solid #e5e5e5;
max-width: 940px;
text-align: center;
/*display: table;*/
margin: 0 auto;
}
/* infoBar Bottom Border onHover or Active element*/
#infoBar a:hover,
#infoBar a.active {
border-bottom: 4px solid #2889DE;
text-decoration: none;
}
/* infoBar Link Text */
#infoBar a {
background: transparent;
color: #000;
display: inline-block;
font-size: 16px;
font-family: 'Avenir LT W01 35 Light', Arial, Helvetica, sans-serif;
padding: 1.4em;
text-decoration: none;
}
/* infoBar Link Text onHover */
#infoBar a:Hover {
background: transparent;
color: #2889DE;
display: inline-block;
font-size: 16px;
font-family: 'Avenir LT W01 35 Light', Arial, Helvetica, sans-serif;
padding: 1.4em;
text-decoration: none;
}
/* infoBar Active element */
#infoBar a.active {
font-family: 'Avenir LT W01 65 Medium', Arial, Helvetica, sans-serif;
}
/* Media Queries */
#media screen and (max-width: 960px) {
#infoBar a {
font-size: 14px;
}
}
#media screen and (max-width: 830px) {
#infoBar a {
padding: 1em 0.6em;
}
}
#media screen and (max-width: 760px) {
#infoBar {
display: none;
}
}
/*-- END INFOBAR --*/
/* PAGE SECTIONS
--------------------------- */
/* Page Section Styling */
.page-section {
background-position: center top;
color: #4d4d4d;
min-height: 200px;
padding: 60px 0;
text-align: center;
width: 940px;
margin: auto;
}
/* Page Section - Header2 Styling */
.page-section h2 {
font-size: 24px;
margin-bottom: 20px;
}
/* Page Section Paragraph Styling */
.page-section p {
color: #333;
font-size: 18px;
line-height: 1.5;
/*margin: 10px 0 45px 0;*/
}
/* Foreword-Section-Top Styling */
.foreword-section-top {
padding: 0;
min-height: 160px;
}
/* Foreword-Section-Top Header1 Styling*/
.foreword-section-top h1 {
color: #222;
font-size: 36px;
}
/* Foreword-Section-Top Paragraph Styling */
.foreword-section-top p {
color: #4d4d4d;
margin-bottom: 10px;
}
.grid-100 {
width: 100%;
margin: auto;
}
/* CONTENT PANELS
----------------------------- */
/* Capabilties Panel*/
#capabilities-panel {
max-width: 980px;
margin: 0 auto;
display:block;
}
/*Tutorials Panel */
#tutorials-panel {
max-width: 980px;
margin: 0 auto;
display:none;
}
.product-row {
margin-bottom: 50px;
/*width: 100%; */
max-width: 940px;
margin: 0 auto;
display: inline-block;
}
.product-box {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
float: left;
overflow: hidden;
margin: 0.5%;
position: relative;
text-align: center;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
width: 24%;
}
#media screen and (max-width: 960px) {
.product-box {
width: 48%;
}
}
#media screen and (max-width: 480px) {
.product-box {
display: block;
float: none;
margin: 10px auto;
width: 95%;
}
}
.product-box a {
color: #FFF;
display: block;
font-weight: bold;
}
.product-box a:hover .inner-box-padding {
position: relative;
width: 100%;
-ms-transform: scale(1.1);
-moz-transform: scale(1.1);
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
.product-box .inner-box-padding {
background-color: #007ac2;
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
-ms-transition: all .2s ease-in-out;
-moz-transition: all .2s ease-in-out;
-webkit-transition: all .2s ease-in-out;
transition: all .2s ease-in-out;
width: 100%;
}
.product-box .inner-box-padding:before {
content: "";
display: block;
padding-top: 87%;
}
.product-box h3 {
font-size: 22px;
color: #FFF;
position: absolute;
left: 0;
right: 0;
bottom: 0;
}
.product-box.dark-text h3 {
color: #333;
}
.product-box .capability-one {
background-image: url('http://i64.tinypic.com/2mi16l1.png');
}
.product-box .capability-two {
background-image: url('http://i68.tinypic.com/10gwm75.png');
}
.product-box .capability-three {
background-image: url('http://i65.tinypic.com/5djxwh.png');
}
.product-box .capability-four {
background-image: url('http://i67.tinypic.com/15e7hu8.png');
}
.product-box .tutorial-one {
background-image: url('http://i68.tinypic.com/efhvfc.png');
}
.product-box .tutorial-two {
background-image: url('http://i66.tinypic.com/50199u.png');
}
.product-box .tutorial-three {
background-image: url('http://i63.tinypic.com/wvwcif.png');
}
.product-box .tutorial-four {
background-image: url('http://i67.tinypic.com/1zp1or8.png');
}
/* END PRODUCT BOXES */
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<!-- include jQuery -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
<!-- INFO BAR -->
<div id="infoBar">
Capabilities
Tutorials
Use Cases
Services
Security
What's New
Request Access
</div>
<!-- END GIS INFO BAR -->
<!-- FOREWORD -->
<div class="page-section foreword-section-top">
<h1>Some Cool Tagline</h1>
<p>blah blah blah. We're so awesome. Now give us money.</p>
</div>
<!-- CAPABILITIES PANEL -->
<div id="capabilities-panel" class="panel">
<!-- Capability One -->
<div class="product-box">
<a href="/capabilities/capability-one">
<div class="inner-box-padding capability-one"></div>
<h3>Capability 1</h3>
</a>
</div>
<!-- Capability Two box -->
<div class="product-box dark-text">
<a href="/capabilities/capability-two">
<div class="inner-box-padding capability-two"></div>
<h3>Capability 2</h3>
</a>
</div>
<!-- Capability Three box -->
<div class="product-box">
<a href="/capabilities/capability-three">
<div class="inner-box-padding capability-three"></div>
<h3>Capability 3</h3>
</a>
</div>
<!-- Capability Four box -->
<div class="product-box">
<a href="/capabilities/capability-four">
<div class="inner-box-padding capability-four"></div>
<h3>Capability 4</h3>
</a>
</div>
</div>
<!-- END CAPABILITIES PANEL -->
<!-- TUTORIALS PANEL -->
<div id="tutorials-panel" class="panel">
<!-- Tutorial One box -->
<div class="product-box">
<a href="/tutorials/tutorial-one">
<div class="inner-box-padding tutorial-one"></div>
<h3>Tutorial 1</h3>
</a>
</div>
<!-- Tutorial Two box -->
<div class="product-box dark-text">
<a href="/tutorials/tutorial-two">
<div class="inner-box-padding tutorial-two"></div>
<h3>Tutorial 2</h3>
</a>
</div>
<!-- Tutorial Three box -->
<div class="product-box">
<a href="/tutorials/tutorial-three">
<div class="inner-box-padding tutorial-three"></div>
<h3>Tutorial 3</h3>
</a>
</div>
<!-- Tutorial Four box -->
<div class="product-box">
<a href="/tutorials/tutorial-four">
<div class="inner-box-padding tutorial-four"></div>
<h3>Tutorial 3</h3>
</a>
</div>
</div>
<!-- END TUTORIALS PANEL -->

Pretty sure that this might do something like you'd want.
There are more elegant pieces of code (not to mention that there should be loads of plugins) for this though, this is just out of the top of my head (dont use $.attr to find the corresponding panel etc).
$(document).ready(function(){
$(".navItem").click(function(event) {
event.preventDefault();
$('.navItem').removeClass("active").removeClass("on");
$(this).addClass("active").addClass("on");
var panel = $(this).attr('panel-id');
$(".panel").hide();
$("#"+panel).show();
});
});
In order to use this script you need to import jQuery into your page though, which literally putting 1 line in your page (just google that).
You need to give every panel the class panel (i.e. instead of just the 'id' attribute. This will allow for the $(".panel") to find all html that is in a
The var panel = $(this).attr('panel-id'); line finds the panel belonging to the anchor the user clicked, as long as you add an attribute to each anchor containing the id of the corresponding panel as the value (e.g. <a (..) panel-id="capabilities-panel">)
=======
Updated answer so OP can use vanilla javascript per his request.
(function () {
alert('hello');
var links = document.getElementsByClassName("navItem");
for (i = 0; i < links.length; i++) {
var link = links[i];
link.addEventListener('click',function(event) {
event.preventDefault();
for(int k = 0; k < links; k++) {
links[k].className = "navItem";
}
event.target.className += " active on";
var panels = document.getElementsByClassName("panel");
for (j = 0; j < panels.length; j++) {
panels[j].style.display = 'none';
}
var panel_id = event.target.getAttribute("panel-id");
document.getElementById(panel_id).style.display = 'block';
});
}
})();
I haven't tested this so there's probably some syntactic errors here and there, and Im not too sure how one gets the sender element from a click event in vanilla javascript (though this shouldn't be too hard to google).
You need to put scripts in between <script></script> tags in order for your browser to recognize javascript.
Note how the number of lines and readability decreased by abandoning jQuery.
Hope this helps you!
Also, if this is just not working for you I recommend checking out the link the other guy posted under your question.

Related

combine tabs and grid layout

I'm currently learning, please bear with me. I try to make a holy grail layout using grid while making tabs to change middle content (and maybe left one in the future).
I used this suggestion I found here to make the tabs : https://jsfiddle.net/a2fh8n4e/
$(document).ready(function () {
var previousActiveTabIndex = 0;
$(".tab-switcher").on('click', function (event) {
if (event.type === "click") {
var tabClicked = $(this).data("tab-index");
if(tabClicked != previousActiveTabIndex) {
$("#allTabsContainer .tab-container").each(function () {
if($(this).data("tab-index") == tabClicked) {
$(".tab-container").hide();
$(this).show();
previousActiveTabIndex = $(this).data("tab-index");
return;
}
});
}
}
});
});
html {
background-color: #aaaaaa;
font-size: 16px;
font-family: "alegreya", serif;
}
body {
min-width: 550px;
margin: 0;
padding: 0 20px 20px 20px;
display: grid;
grid-template-columns: 15% auto 15%;
grid-template-areas: "header header header" "left middle right" "footer footer footer";
}
#header {
border-width: 2px, 2px, 0, 2px;
border-color: #ccc;
border-style: solid;
margin-top: 10px;
}
#left {
border-width: 4px, 1px, 0px, 2px;
border-color: #ccc;
border-style: solid;
}
#middle {
border-width: 0, 1px, 2px, 1px;
border-color: #ccc;
border-style: solid;
}
#right {
border-width: 0, 2px, 2px, 1px;
border-color: #ccc;
border-style: solid;
padding-left: 3px;
}
#footer {
background: #ccc;
height: 40px;
padding-top: 10px;
position: absolute;
bottom: 0;
left: 0;
right: 0;
text-align: right;
}
.tab-switcher {
display: inline-block;
cursor: pointer;
margin-right: 25px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- HEADER AND TABS -->
<div style="grid-area: header" id="header">
<ul>
<li class="tab-switcher" data-tab-index="0" tabindex="0">Collecte</li>
<li class="tab-switcher" data-tab-index="1" tabindex="0">Journal</li>
</ul>
</div>
<!-- CONTENT ZONE -->
<div id="allTabsContainer">
<div class="tab-container" data-tab-index="0">
<!-- TAB1 -->
<div style="grid-area: left" id="left">
<p>Wood : <span id="Wood"></span></p>
</div>
<div style="grid-area: middle" id="middle">
<button class="Collect" id="But_wood">Pick wood</button>
<button class="Collect" id="But_tree">Cut a tree</button>
</div>
</div>
<div class="tab-container" data-tab-index="1" style="display:none;">
<!-- TAB2 -->
<div style="grid-area: left" id="left">
<p>Stone : <span id="Stone"></span></p>
<p>Grass : <span id="Grass"></span></p>
</div>
<div style="grid-area: middle" id="middle">
<button class="Collect" id="But_stone">Collect stone</button>
<button class="Collect" id="But_grass">Collect grass</button>
</div>
</div>
<!--div class="tab-container" data-tab-index="2" style="display:none;">
Some content for Tab - 3
</div-->
</div>
<!-- LOGS & CHAT SHOULD BE ALWAYS ACTIVE -->
<div style="grid-area: right" id="right">
<p>Logs</p>
<p id="log">...</p>
</div>
<!-- FOOTER SHOULD BE ALWAYS ACTIVE -->
<div style="grid-area: footer" id="footer">
<p>contenu relatif au site et à l'auteur</p>
</div>
<!-- MISC. & SCRIPTS -->
<script src="scripts/main.js"></script>
I tried to combine the two but can't reach something where it works as intended with the correct layout. I can not combine style="grid-area: xxx within the selected tabs https://jsfiddle.net/j6cemskg/35/
=> I want the buttons to be in the middle column, while having ressources amount on a left panel, and both should change according to tab chosen.
Also, if anyone can give insight on how to avoid the trouble to have multiple ID like "left0","left1", etc. for each and every tab (maybe class attribute ? Can I have multiple classes assigned to a same element ?)
I would gladly take any advice concerning those troubles, thank you.
One approach is as follows, but I've changed quite a bit of your code to simplify things.
Basically, I've adjusted your HTML so that the grid display is based on the #allTabsContainer element, and made all elements that make up areas of that grid siblings in order that they can be placed in the grid defined on the #allTabsContainer element.
I've also removed the jQuery entirely, and revised the approach used to toggle the display of the various grid-elements.
Explanatory comments for changes, and functionality, are in the code below:
// defining a named function using Arrow syntax, to which a reference to the
// Event Object is passed (automatically) from EventTarget.addEventListener():
const updateToggle = (evt) => {
// we retrieve the element that has triggered the function-call to
// which the function was bound:
let switched = evt.currentTarget,
// from that element we use the HTMLElement.dataset API to
// retrieve the value of the named attribute; we use camelCase
// to access attributes that include hyphens; so 'data-tab-index'
// is accessed as below:
toShow = switched.dataset.tabIndex,
// from the switched element we navigate to the closest ancestor
// that contains a 'data-tab-show' attribute:
toggleDispatch = switched.closest('[data-tab-show]');
// with that Element we - again - utilise the HTMLElement.dataset
// API to set the the 'data-to-show' attribute-value to the value
// we retrieved from the clicked ('switched') element:
toggleDispatch.dataset.tabShow = toShow;
},
// here we retrieve the elements that will serve as switches, the
// li.tab-switcher elements:
toggles = document.querySelectorAll('li.tab-switcher');
// we use NodeList.prototype.forEach() to iterate over the NodeList:
toggles.forEach(
// here we use an Arrow function to bind the updateToggle() function
// (note the deliberately omitted parentheses) as the event-handler
// for the 'click' event on the elements of the NodeList:
(el) => el.addEventListener('click', updateToggle)
);
/* simple reset to ensure that all elements are using the same
box-sizing algorithm, font, list-style-type, margin and padding */
*, ::before, ::after {
box-sizing: border-box;
font: normal normal 1rem / 1.5 sans-serif;
list-style-type: none;
margin: 0;
padding: 0;
}
#allTabsContainer {
display: grid;
/* setting a 0.5em gap between adjacent elements,
whether vertically, or horizontally, adjacent: */
gap: 0.5em;
grid-template-areas:
"header header header"
"left middle right"
"footer footer footer";
/* there are differences between 'auto' and '1fr'
but they're minor, and your intent seems to be
to use the entirety of the space available, so
I chose to replace 'auto' with '1fr': */
grid-template-columns: 15% 1fr 15%;
/* using grid-template-rows to specify the heights
of the various rows: */
grid-template-rows: min-content 1fr 50px;
/* setting a margin on the block-axis of the element
to 0 (this is implicit from the 'reset' above; but
if it needs to be changed I like it to be explicitly
stated for ease of changing) the 'block-axis' is
top-to-bottom in English and left-to-right languages: */
margin-block: 0;
/* I put a margin of 20px on the inline-axis (the axis of
writing-flow, left-to-right in English): */
margin-inline: 20px;
/* this makes the minimum height of the element 100 viewport-units
tall, but allows it to expand if the content demands it: */
min-height: 100vh;
}
#allTabsContainer > div {
/* placing a border on all elements taking part in the grid: */
border: 2px solid #ccc;
}
#header {
/* positioning the grid-element in the named grid-area: */
grid-area: header;
}
#header ul {
/* using flex-layout to arrange the elements to flow in the
inline axis: */
display: flex;
/* placing a 1em gap between adjacent elements: */
gap: 1em;
/* vertically aligning the child elements: */
align-content: center;
/* aligning the child elements to the start of the inline-flow
(to the left in a left-to-right language such as English): */
justify-content: start;
}
.tab-switcher {
cursor: pointer;
/* setting the defaults for the text-decoration
(not using 'text-decoration' shorthand): */
text-decoration-color: transparent;
text-decoration-line: underline;
text-decoration-thickness: 0.1em;
/* transitioning all properties: */
transition: all 0.3s linear;
}
/* selects all .tab-switcher elements when they match
any of the supplied pseudo-classes listed in the :is()
pseudo-class: */
.tab-switcher:is(:hover, :active, :focus) {
color: rebeccapurple;
text-decoration-color: currentColor;
text-decoration-line: underline;
text-decoration-thickness: 0.2em;
}
/* positioning elements in the named grid-areas: */
.tab-container.left {
grid-area: left;
}
.tab-container.middle {
grid-area: middle;
}
#right {
grid-area: right;
}
#footer {
background-color: #ccc;
grid-area: footer;
padding-inline: 1em;
/* again using CSS logical properties, here we align the text
to the end of the inline-axis (the right, in a left-to-right
language such as English): */
text-align: end;
}
/* here we select all element(s) which are not a '.tab-switcher'
element which have a data-tab-index attribute and are a
descendant of an element(s) with a data-tab-show attribute: */
[data-tab-show] [data-tab-index]:not(.tab-switcher) {
/* we visually hide those elements (this may be imperfect for
use in non-visual media, such as screen-readers; please check): */
opacity: 0;
visibility: hidden;
}
/* here we undo the hiding of those elements, by selecting elements which
are not '.tab-switcher' elements, that have a data-tab-index
attribute-value equal to 0 (or 1) which is a descendant of an element(s)
that have a data-tab-show attribute-value of 0 (or 1): */
[data-tab-show="0"] [data-tab-index="0"]:not(.tab-switcher),
[data-tab-show="1"] [data-tab-index="1"]:not(.tab-switcher) {
opacity: 1;
visibility: visible;
}
button {
/* adding padding to the <button> elements, purely for aesthetic purposes: */
padding-block: 0.2em;
padding-inline: 0.4em;
}
<!-- the grid display is now specified on the following element, and all elements taking part
in the grid are now siblings; this is so that they're all 'aware' of the grid in their
parent element and can be positioned in those areas.
You'll note that there is a new data-* attribute, the "data-tab-show" attribute with a
value set to 0 on page-load (this is modified in the JavaScript that handles the
toggling: -->
<div id="allTabsContainer" data-tab-show="0">
<!-- HEADER AND TABS -->
<div id="header">
<ul>
<li class="tab-switcher" data-tab-index="0" tabindex="0">Collecte</li>
<li class="tab-switcher" data-tab-index="1" tabindex="0">Journal</li>
</ul>
</div>
<!-- CONTENT ZONE -->
<!-- I've also removed the id for the #middle0, #middle1, #left0, #left1...
elements, since it did nothing particularly useful and made it more
awkward to position those elements; instead I added a class to make
it easier ('middle' and 'left') to allow for positioning within
the grid: -->
<div class="tab-container middle" data-tab-index="0">
<!-- TAB1 -->
<button class="Collect" id="But_wood">Pick wood</button>
<button class="Collect" id="But_tree">Cut a tree</button>
</div>
<div class="tab-container middle" data-tab-index="1">
<!-- TAB2 -->
<button class="Collect" id="But_stone">Collect stone</button>
<button class="Collect" id="But_grass">Collect grass</button>
</div>
<div class="tab-container left" data-tab-index="0">
<p>Wood : <span id="Wood"></span></p>
</div>
<div class="tab-container left" data-tab-index="1">
<p>Stone : <span id="Stone"></span></p>
<p>Grass : <span id="Grass"></span></p>
</div>
<!-- LOGS & CHAT SHOULD BE ALWAYS ACTIVE -->
<div id="right">
<p>Logs</p>
<p id="log">...</p>
</div>
<!-- FOOTER SHOULD BE ALWAYS ACTIVE -->
<div style="grid-area: footer" id="footer">
<p>contenu relatif au site et à l'auteur</p>
</div>
</div>
<!-- MISC. & SCRIPTS -->
<!-- commented out as it causes a GET error in the console on sites
where this script doesn't exist (and while I'm looking at the
console for errors it's distracting to have an expected error
there:
<script src="scripts/main.js"></script>
-->
JS Fiddle demo.
References:
CSS:
align-content.
Attribute-selectors [attr], [attr="value"].
box-sizing.
display.
font.
gap.
grid-area.
grid-template-areas.
grid-template-columns.
grid-template-rows.
:is().
justify-content.
Logical properties.
:not().
text-align.
JavaScript:
Arrow functions.
document.querySelectorAll().
HTMLElement.dataset API.
NodeList.prototype.forEach().
Here I will concentrate on the layout using the grid with 4 areas.
I will then show how to handle clicks of the tabs and some actions related to that using a "target" data attribute.
I will leave the style of color etc. to you but put borders on to illustrate each area.
$(function() {
$(".tab-switcher").on('click', function(event) {
let tabClicked = $(this).data("tabTarget");
let lastTab = $(this).closest(".tab-switcher-list").data("last-clicked");
$("#allTabsContainer .tab-container").hide().filter(tabClicked).show();
}).first().trigger('click');
});
html {
/* background-color: #aaaaaa; out just because I dislike gray for visually challenged people reasons */
font-size: 16px;
font-family: "alegreya", serif;
}
body {
/* min-width: 550px; */
margin: 0;
padding-top: 0;
padding-right: 1em;
padding-left: 1em;
padding-bottom: 1em;
border: solid 1px lime;
}
.page-container {
display: grid;
grid-template: auto 1fr auto / auto 1fr auto;
}
.container-header {
padding: 1rem;
grid-column: 1 / 4;
}
.container-left {
grid-column: 1 / 2;
}
.container-main {
grid-column: 2 / 3;
}
.container-right {
grid-column: 3 / 4;
}
.container-footer {
grid-column: 1 / 4;
}
.container-header {
border: solid red 1px;
}
.page-pane {
/* base style for all panes */
border-color: #CCCCCC;
border-style: solid;
border-top-width: 0.125em;
border-left-width: 0.125em;
border-bottom-width: 0.125em;
border-right-width: 0.125em
}
.container-left {
border-right-width: 0.0625em;
border-color: cyan;
}
.container-main {
min-height: 20rem;
}
.container-right {
border-right-width: 0.0625em;
border-color: magenta;
padding-left: 0.5em;
}
.container-footer {
grid-column: 1 / 4;
text-align: right;
align-self: end;
}
.tab-switcher-container {
display: flex;
justify-content: center;
border: solid orange 0.0875em;
height: 2.5rem;
}
nav .tab-switcher-list {
display: flex;
justify-content: center;
list-style-type: none;
border-bottom: 0.25em solid #444444;
height: 1.25em;
}
.tab-switcher {
flex: auto;
margin: 0.25em;
background-color: #EEEEEE;
cursor: pointer;
border: 1px solid #44ddCC;
height: 1.25rem;
padding-left: 0.25em;
padding-right: 0.25em;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="page-container">
<div class="container-header page-pane">
<div>I am the header pane</div>
<nav class="tab-switcher-container">
<ul class=tab-switcher-list>
<li class="tab-switcher" data-tab-target=".tab-1">Collecte</li>
<li class="tab-switcher" data-tab-target=".tab-2">Journal</li>
<li class="tab-switcher" data-tab-target=".tab-cheese">Cheese</li>
</ul>
</nav>
</div>
<div class="container-left page-pane">
<div>I am the left pane</div>
<div id="allTabsContainer">
<div class="tab-container tab-1" data-tab-index="0">
<div>
<p>Wood:<span>I am wood, get wood</span></p>
</div>
</div>
<div class="tab-container tab-2" data-tab-index="1">
<div>
<p>Stone:<span>I am stone, get stone</span></p>
<p>Grass:<span>Grass I am - why am in in stone?!</span></p>
</div>
</div>
<div class="tab-container tab-cheese" data-tab-index="1">
<div>
<p>Cheese:<span>I am cheese!</span></p>
<p>Flavor:<span>Cheddrer Cheese!</span></p>
</div>
</div>
</div>
</div>
<div class="container-main page-pane">
<div>I am the main pane</div>
<button class="Collect get-wood">Pick wood</button>
<button class="Collect cut-tree">Cut a tree</button>
<button class="Collect get-stone">Collect stone</button>
<button class="Collect get-grass">Collect grass</button>
<p>Here I am make me happy</p>
<p>Here I am make me happy</p>
<p>Here I am make me happy</p>
</div>
<div class="container-right logs-container page-pane">
<div>I am the right page pane</div>
<p>Logs</p>
<p id="log">...</p>
</div>
<div class="container-footer page-pane">
<div>I am the footer pane</div>
<div>
<p>contenu relatif au site et à l'auteur</p>
</div>
</div>
</div>

Using CSS Transitions on Auto Height Dimensions

I'm making a collapsible panel and the issue is with the [data-panel] not keeping the css transition when it's set to height: 100%. it works fine for fixed height i.e. height: 150px , but it's important to keep height dynamic since I don't know the available space of the content inside. i'd prefer not modifying the html or js but i'm open to suggestions...
Codepen: issue on line 44 in css
https://codepen.io/oneezy/pen/bGBpXaW
function activeLinks() {
document.addEventListener('click', e => {
let linkEl = e.target.closest('[data-link]');
if (linkEl) {
let url = linkEl.dataset.link;
let linkEls = document.querySelectorAll('[data-link]');
let ActivelinkEls = document.querySelectorAll(`[data-link="${url}"]`);
// remove "active" class from all links
Array.from(linkEls).forEach( (el) => {
el.classList.remove('active');
});
// add "active" class to all matching links
Array.from(ActivelinkEls).forEach( (el) => {
let prevLink = el.parentElement.previousElementSibling;
let prevPrevLink = el.parentElement.parentElement.previousElementSibling;
el.classList.add('active');
if (prevLink && prevLink.dataset.link) {
prevLink.classList.add('active');
prevLink.parentElement.classList.add('active');
}
if (prevPrevLink && prevPrevLink.dataset.link) {
prevPrevLink.classList.add('active');
prevPrevLink.parentElement.classList.add('active');
}
});
}
});
}
activeLinks();
/* Reset
*********************************/
* { margin: 0; padding: 0; box-sizing: border-box; font-family: roboto; }
html, body { height: 100%; overflow-x: hidden; }
a { text-decoration: none; display: block; }
/* Layout
*********************************/
#page { display: grid; grid-template-columns: 160px 1fr; gap: 3rem; height: 100%; }
#nav { background: black; display: block; align-items: start; align-content: start; justify-content: stretch; padding: 2rem 1rem; }
#main { display: flex; justify-content: space-around; padding: 2rem 5rem 0 0; }
/* Navigation
*********************************/
/* Sections */
#nav .link-level__one { margin: 1rem 0; }
#nav .link-level__two { }
#nav .link-level__three { position: relative; }
#nav .link-level__three::after { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px; width: 100%; background: gray; }
/* Links */
#nav .link-level__one a { padding: .25rem .5rem; color: gray; font-weight: 900; }
#nav .link-level__one a.active { color: white; }
#nav .link-level__two a { padding: .25rem .5rem; color: gray; font-weight: normal; }
#nav .link-level__two a.active { color: white; }
#nav .link-level__three a { padding: .25rem .5rem; color: gray; }
#nav .link-level__three a.active { color: white; font-weight: normal; }
/* Main
*********************************/
#main section { }
#main a { color: black; padding: 1rem .5rem; }
#main a.active { background: blue; color: white; }
/* Panel
*********************************/
[data-panel] { height: 0; overflow: hidden; transition: .22s .22s ease-in-out; }
.active ~ [data-panel] { height: 150px; } /* I NEED THIS TO BE DYNAMIC HEIGHT! */
<div id="page">
<nav id="nav">
<!-- LINK 1
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
<!-- LEVEL 1 -->
<section class="navigation-links__wrapper link-level__one">
Link 1
<!-- LEVEL 2 -->
<section class="link-level__two" data-panel>
Link 1a
<!-- LEVEL 3 -->
<section class="link-level__three" data-panel>
Link 1a-1
Link 1a-2
Link 1a-3
</section>
</section>
</section>
<!-- LINK 2
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
<!-- LEVEL 1 -->
<section class="navigation-links__wrapper link-level__one">
Link 2
<!-- LEVEL 2 -->
<section class="link-level__two" data-panel>
Link 2a
<!-- LEVEL 3 -->
<section class="link-level__three" data-panel>
Link 2a-1
Link 2a-2
Link 2a-3
</section>
</section>
</section>
<!-- LINK 3
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
<!-- LEVEL 1 -->
<section class="navigation-links__wrapper link-level__one">
Link 3
<!-- LEVEL 2 -->
<section class="link-level__two" data-panel>
Link 3a
<!-- LEVEL 3 -->
<section class="link-level__three" data-panel>
Link 3a-1
Link 3a-2
Link 3a-3
</section>
</section>
</section>
</nav>
<main id="main">
<section>
<h2>Link Level 1</h2>
Link 1
Link 2
Link 3
</section>
<section>
<h2>Link Level 2</h2>
Link 1a
Link 2a
Link 3a
</section>
<section>
<h2>Link Level 3</h2>
Link 1a-1
Link 1a-2
Link 1a-3
Link 2a-1
Link 2a-2
Link 2a-3
Link 3a-1
Link 3a-2
Link 3a-3
</section>
</main>
</div>
It's a duplicate question that has been answered here:
How can I transition height: 0; to height: auto; using CSS?
You can use a max-height greater than it will ever be to accomplish this.
#menu #list {
max-height: 0;
transition: max-height 1s ease-out;
overflow: hidden;
background: #d5d5d5;
}
#menu:hover #list {
max-height: 1000px;
transition: max-height 1s ease-in;
}
I've somewhat came up with a solution I'm proud of; however, it's not perfect. The main trick in getting this to work was giving the [data-panel] a line-height: 0 and transitioning it when it becomes active (THE LINE-HEIGHT ONLY). Also you'll need to make sure the contents of the [data-panel] don't have any margin or padding (until the panel becomes active) or it will completely throw off the UI.
https://codepen.io/oneezy/pen/bGBBEmp
/* Panel
*********************************/
[data-panel] {
overflow: hidden;
line-height: 0;
opacity: 0;
pointer-events: none;
transition: line-height .22s ease-in-out;
}
.active + [data-panel] {
line-height: 1.4;
opacity: 1;
pointer-events: auto;
}
I'm answering my own question; however, I'm not accepting it as the chosen answer. I'd love to see more unique solutions added to this thread.
The short answer is that you can't. Height transitions will only work on elements that use a unit based value for their height property.
Here's an article detailing different techniques to achieve the same outcome: https://css-tricks.com/using-css-transitions-auto-dimensions/

Align ':after plus/minus sign' Centrally Within Button

I'm using an Accordion which is built of buttons, I've got the 'plus' and 'minus' signs as ':after'
So far I've tried 'justify-content: center' within the button, I've also tried 'vertical-align: middle', neither had any effect and when I tried to wrap a div around the button to implement the styling on that button, it stopped the accordion from working.
I also am having trouble when on a thin screen the plus sign is coming into the text, it's currently floating to the right but there is no designated space between them to stop a crossover.
All the code I've tried to use to centrally align this element i haven't got to work, please see below:
Here is the code:]
HTML:
<button class="accordion">Where is your company located?</button>
<div class="panel">
<p class="zpa-regular2">We are located in the heart of San Francisco, California USA! We do have shipping warehouses located in the USA, Europe, and Asia to ensure the quickest delivery for your location.</p>
</div>
<button class="accordion">What is the warranty and return policy?</button>
<div class="panel">
<p class="zpa-regular2"><span>We have a Risk-Free Policy. During this promotion - you can try the product for 30 days - if you decide for whatever reason this is not for you then you can return the device for a full refund.</span></p>
</div>
<button class="accordion">Does the product have a specific method of operation? Is it easy to use?</button>
<div class="panel">
<p class="zpa-regular2">Yes! It is very simple and easy to use. You will receive a detailed user manual with positions and pointers to maximize your results. :)</p>
</div>
CSS:
.accordion {
background-color: white;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
text-align: left;
border: none;
outline: none;
transition: 0.4s;
color: #262626;
font-size: 18px;
font-weight: 700;
font-style: normal;
font-family: 'Lato';
}
/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
.active, .accordion:hover {
background-color: white;
}
/* Style the accordion panel. Note: hidden by default */
.panel {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
.accordion:after {
content: '\02795'; /* Unicode character for "plus" sign (+) */
font-size: 18px;
font-family: 'Lato';
color: #262626;
float: right;
margin-left: 5px;
}
.active:after {
content: "\2796"; /* Unicode character for "minus" sign (-) */
}
The javascript, incase it helps at all:
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
Thanks if you can help.
Dale.
May be this can help you. I added an <span> due to control both parts and then display: flex;
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
.accordion {
background-color: red;
color: #444;
cursor: pointer;
width: 100%;
text-align: left;
outline: none;
transition: 0.4s;
color: #262626;
font-size: 18px;
font-weight: 700;
font-style: normal;
font-family: 'Lato';
border: 0;
margin: 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: 18px;
}
/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
.active, .accordion:hover {
background-color: white;
}
/* Style the accordion panel. Note: hidden by default */
.panel {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
.accordion span:after {
content: '\02795'; /* Unicode character for "plus" sign (+) */
font-size: 18px;
font-family: 'Lato';
color: #262626;
padding-left: 20px;
}
.accordion.active span:after {
content: "\2796"; /* Unicode character for "minus" sign (-) */
}
<button class="accordion">Where is your company located? <span></span></button>
<div class="panel">
<p class="zpa-regular2">We are located in the heart of San Francisco, California USA! We do have shipping warehouses located in the USA, Europe, and Asia to ensure the quickest delivery for your location.</p>
</div>
<button class="accordion">What is the warranty and return policy?<span></span></button>
<div class="panel">
<p class="zpa-regular2"><span>We have a Risk-Free Policy. During this promotion - you can try the product for 30 days - if you decide for whatever reason this is not for you then you can return the device for a full refund.</span></p>
</div>
<button class="accordion">Does the product have a specific method of operation? Is it easy to use?<span></span></button>
<div class="panel">
<p class="zpa-regular2">Yes! It is very simple and easy to use. You will receive a detailed user manual with positions and pointers to maximize your results. :)</p>
</div>
This answer is based on the practical behavior of concerned css properties to achieve vertical align of minus sign and plus sign inside button(I haven't tried for other elements like span or div but I believe it works the same, if not pardon my guess) upon increasing the font-size(to any extent) regardless of font-family used.
Consider this an alternative to what has already been answered by Alberto Rhuetras.
Use Case: Sometimes you want bigger buttons with a plus or minus sign inside it. But the font-size is too small for the button. As you increase the font-size of the button, the plus and minus sign fails to align vertically as was the case with me. That's when I came up with the following solution.
Note: I could't find a solution anywhere else, so I ended up with this solution. I am open to any say you have on the solution so feel free to leave some comments:)
/* common style */
.minus, .plus {
height: 50px;
width: 200px;
background: #216AFF;
color: white;
}
.minus {
font-size: 70px;
display: flex;
justify-content: center;
line-height: 35px;
}
.plus {
font-size: 50px;
display: flex;
justify-content: center;
line-height: 45px;
}
.demo {
font-size: 18px;
padding: 18px;
width: 100%;
text-align: left;
display: flex;
}
.demo::after {
content: "\02795";
font-size: 18px;
float: right;
line-height: 23px;
justify-content: center;
align-content: flex-start;
}
<button class="minus">-</button>
<br>
<button class="plus">+</button>
<br>
<button class="demo">Does the product have a specific method of operation? Is it easy to use? What is the warranty and return policy?</button>
Use display-flex on the button and use the value of line-height to position the plus or minus sign vertically within the button. Increase in line-height value moves the signs downward and and decrease in line-height value moves the signs upward. Thanks!

How to make the modal scrollbar replacing the body scrollbar temporary without moving its contents to the right?

I created a Modal. Everything went well. When there are lot of contents, a vertical scrollbar will show up.
The problem is if the body page and the modal have both a lot of contents there will be two vertical scrollbars.
Here an example:
function showModal() {
// Hide Body Scrollbar
// document.body.style.overflow = "hidden";
document.getElementById("myModal").style.display="block";
// When the user clicks anywhere outside of the modal, close it
var modal = document.getElementById("myModal");
window.onclick = function(event) {
if (event.target == modal) {
//modal.style.display = "none";
closeModal();
}
}
}
function closeModal() {
// Show Body Scrollbar
// document.body.style.overflow = "visible";
document.getElementById("myModal").style.display="none";
}
.modal {
display: none;
position: fixed;
z-index: 2;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
}
.modalContent {
border-radius: 10px;
background-color: #fefefe;
margin: 10% auto; /* 15% from the top and centered */
padding: 0;
border: 1px solid #888;
width: 50%; /* Could be more or less, depending on screen size */
overflow: hidden;
}
.modal .modalHeader {
font-family: 'Ubuntu', Arial;
font-weight: bold;
padding: 10px;
margin: 0;
}
.modal .modalHeader span {
color: #7788C9;
letter-spacing: 4px;
}
.modal .modalHeader .close {
color: #000;
float: right;
padding: 0 10px;
}
.clear-close{clear:right;display: block;}
.modal .modalBody {
background-color: #FFF;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
color: #000;
position: static;
padding: 10px;
margin: 0;
}
.modal .modalFooter {
padding: 10px;
margin: 0;
text-align: right;
}
<center>
<h1>Modal</h1>
<button onClick="showModal()">
Show Modal
</button>
<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
</center>
<div id="myModal" class="modal">
<div id="abc" class="modalContent">
<div class="modalHeader">
<span>Modal</span>
X
</div>
<div class="modalBody clear-close">
This is the modal content.
<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
</div>
<div class="modalFooter">
Close
</div>
</div>
</div>
I've my solutions, but they have up and down:
1) Trying to keep the modal as short as possible. Problem is not everyone has the same screen size. So some people might see 2 scrollbars.
2) In my Javascript code, document.body.style.overflow are currently set as a commentary. I uncomment them. When I click Show Modal, it shows 1 scrollbar like I want. But the down is when I click on it, the content behind the modal moves slightly to the right. (When websites is centered)
So, is there a way to show the modal scrollbar only without the body scrollbar and without making the content behind moving slightly to the right and to the left?
We should see 1 scrollbar only when the modal show up.
We should not see the content behind the modal moving slightly to the
right and left when opening and closing.
Note: I'm not allowed to use jQuery

How to build sliding horizontal menu. CSS

I'm trying to build a simple slider that consists of a static 'window' and movable list of items.
where parent container shows only one item and hides all the rest.
I've tried to do something like this but appears this is wrong:
<div id="category-selector">
<div class="categories-list clearfix">
<a class="category">sports</a>
<a class="category">fashion</a>
<a class="category">health</a>
</div>
</div>
#category-selector {
width: 300px; margin: 0 auto; position: relative; z-index: 1;
border: 2px solid #ccc;
-moz-box-sizing: content-box; -webkit-box-sizing: content-box; box-sizing: content-box; height: 55px;
overflow: hidden;
}
.categories-list {
position: absolute; top: 0; left: 0; display: block;
}
a.category {
display: block; float: left; width: 100%; padding: 10px;
font-size: 30px; font-family: Cambria, 'Segoe UI', sans-serif; line-height: 35px;
text-decoration: none; text-align: center; color: #42a6ce;
}
How do I achieve this functionality?
Try this:
.categories-list {
display: block;
white-space: nowrap;
/*margin-left: -300px;*/
}
a.category {
display: inline-block;
width: 280px;
padding: 10px;
font-size: 30px; font-family: Cambria, 'Segoe UI', sans-serif; line-height: 35px;
text-decoration: none; text-align: center; color: #42a6ce;
}
If you want to have links arranged from left to right, you should set them fixed width. If you set 100% then they will always try to fill container. Setring display to inline-block allows us to avoid wraping line by setting white-space: nowrap; on container.
To scroll it just set margin on container for example margin-left: -300px;
Working sample: http://jsfiddle.net/N9R2E/
Alternatively you may try this:
.categories-list {
display: block;
white-space: nowrap;
margin-left: -300px;
width: 10000px; /* long enough to fit all links */
}
a.category {
display: block;
float:left;
width: 280px;
padding: 10px;
font-size: 30px; font-family: Cambria, 'Segoe UI', sans-serif; line-height: 35px;
text-decoration: none; text-align: center; color: #42a6ce;
}
This uses display:block and float:left like in your attempt, but widths are fixed. To have all links in one line categories-list must be wider then all links together.
Working sample: http://jsfiddle.net/N9R2E/3/
If you don't mind using JS or buttons, this is one way to do it.
$(document).ready(function() {
var slider = $("#categoriese_list");
var leftProperty, newleftProperty;
// the click event handler for the right button
$("#right_button").click(function() {
// get value of current left property
leftProperty = parseInt(slider.css("left"));
// determine new value of left property
if (leftProperty - 100 <= -900) {
newLeftProperty = 0; }
else {
newLeftProperty = leftProperty - 100; }
// use the animate function to change the left property
slider.animate( {left: newLeftProperty}, 1000);
}); // end click
// the click event handler for the left button
$("#left_button").click(function() {
// get value of current right property
leftProperty = parseInt(slider.css("left"));
// determine new value of left property
if (leftProperty < 0) {
newLeftProperty = leftProperty + 100;
}
else {
newLeftProperty = -800;
}
// use the animate function to change the left property
slider.animate( {left: newLeftProperty}, 1000);
}); // end click
}); // end ready
However, I would recommend making your categories list out of a <ul> to keep it more in line.
What you're talking about is essentially a carousel or slider. Rather than trying to code it from scratch I would just use one of the million jQuery plugins out there to build this. I personally like bxslider a lot for things like this because it's responsive and very simple to implement.

Categories

Resources