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 data-tab-index="0" tabindex="0">Collecte</li>
<li data-tab-index="1" tabindex="0">Journal</li>
</ul>
</div>
<!-- CONTENT ZONE -->
<div id="allTabsContainer">
<div 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 id="But_wood">Pick wood</button>
<button id="But_tree">Cut a tree</button>
</div>
</div>
<div 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 id="But_stone">Collect stone</button>
<button id="But_grass">Collect grass</button>
</div>
</div>
<!--div 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.
CodePudding user response:
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 data-tab-index="0" tabindex="0">Collecte</li>
<li 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 data-tab-index="0">
<!-- TAB1 -->
<button id="But_wood">Pick wood</button>
<button id="But_tree">Cut a tree</button>
</div>
<div data-tab-index="1">
<!-- TAB2 -->
<button id="But_stone">Collect stone</button>
<button id="But_grass">Collect grass</button>
</div>
<div data-tab-index="0">
<p>Wood : <span id="Wood"></span></p>
</div>
<div 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>
-->
References:
- CSS:
- JavaScript:
CodePudding user response:
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 >
<div >
<div>I am the header pane</div>
<nav >
<ul class=tab-switcher-list>
<li data-tab-target=".tab-1">Collecte</li>
<li data-tab-target=".tab-2">Journal</li>
<li data-tab-target=".tab-cheese">Cheese</li>
</ul>
</nav>
</div>
<div >
<div>I am the left pane</div>
<div id="allTabsContainer">
<div data-tab-index="0">
<div>
<p>Wood:<span>I am wood, get wood</span></p>
</div>
</div>
<div 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 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 >
<div>I am the main pane</div>
<button >Pick wood</button>
<button >Cut a tree</button>
<button >Collect stone</button>
<button >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 >
<div>I am the right page pane</div>
<p>Logs</p>
<p id="log">...</p>
</div>
<div >
<div>I am the footer pane</div>
<div>
<p>contenu relatif au site et à l'auteur</p>
</div>
</div>
</div>