css grid repeat layout style list - javascript

I'm creating a grid of a list of items in a cart and I've made an example of the layout just using the grid area but it doesn't repeat itself to make a list how do I make the grid repeat the boxes layout infinitely
<div class="grid">
<div class="description"></div>
<div class="quantity"></div>
<div class="price"></div>
<div class="close"></div>
<div class="description"></div>
<div class="quantity"></div>
<div class="price"></div>
<div class="close"></div>
<div class="description"></div>
<div class="quantity"></div>
<div class="price"></div>
<div class="close"></div>
</div>
.grid {
width: 300px;
display: grid;
grid-template-columns: auto auto;
}
.close {
height: 50px;
background: red;
grid-area: 1 / 1 / span 1 / span 2;
}
.description {
height: 50px;
background: blue;
grid-area: 2 / 1 / span 1 / span 2;
}
.quantity {
height: 50px;
background: green;
grid-area: 3 / 1 / span 1 / span 1;
}
.price {
height: 50px;
background: pink;
grid-area: 3 / 2 / span 1 / span 1;
}
<h1>I want to repeat this format of grid row items</h1>
<div class="grid">
<div class="description">Description</div>
<div class="quantity">Quantity</div>
<div class="price">Price</div>
<div class="close">Close</div>
<div class="description">Description</div>
<div class="quantity">Quantity</div>
<div class="price">Price</div>
<div class="close">Close</div>
</div>

You can try like below. I am considering translation to rectify the order:
.grid {
width: 300px;
display: grid;
grid-auto-rows:50px;
}
.close {
background: red;
grid-column:span 2;
transform:translateY(-200%);
}
.description {
background: blue;
grid-column:span 2;
transform:translateY(100%);
}
.quantity {
background: green;
transform:translateY(100%);
}
.price {
background: pink;
transform:translateY(100%);
}
<h1>I want to repeat this format of grid row items</h1>
<div class="grid">
<div class="description">Description</div>
<div class="quantity">Quantity</div>
<div class="price">Price</div>
<div class="close">Close</div>
<div class="description">Description</div>
<div class="quantity">Quantity</div>
<div class="price">Price</div>
<div class="close">Close</div>
<div class="description">Description</div>
<div class="quantity">Quantity</div>
<div class="price">Price</div>
<div class="close">Close</div>
</div>

Related

How to center CSS Grid but child elements at the start?

I want to implement this layout with CSS Grid or Flexbox. If necessary, it is also possible to use JS.
In the pictures you can see how the child elements should be arranged when adding 1, 2, 3 and 4 child elements in a sequence
The content is generated dynamically. TThat is, the number of child elements is unknown. There may be a maximum of 3 child elements in a row. The grid items should be centered. The whole Layout should also be responsive.
.parent {
background-color: red;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 20px;
justify-content: center;
/* 3* 350px width of child elements + 2*20px gap*/
max-width: 1090px;
padding: 20px;
}
.child {
width: 350px;
height: 450px;
background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
It is currently not responsive (if possible without media queries) and the child elements are not centered.
Do you know how I can implement this layout?
Don't define 3 columns but rely on implicit column creation:
.parent {
background-color: red;
display: grid;
grid-auto-columns: calc((100% - 2*20px)/3); /* size of one column */
grid-gap: 20px;
justify-content: center;
margin: 10px;
}
.child {
height: 50px;
background-color: blue;
}
/* place each item in the adequate column */
.child:nth-child(3n + 1) {grid-column: 1}
.child:nth-child(3n + 2) {grid-column: 2}
.child:nth-child(3n + 3) {grid-column: 3}
<div class="parent">
<div class="child"></div>
</div>
<div class="parent">
<div class="child"></div>
<div class="child"></div>
</div>
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
I think I have something for this using implicit grids:
* {
box-sizing: border-box;
}
body {
display: flex;
flex-direction: column;
gap: 50px;
background: #000;
}
section {
width: 100%;
padding: 30px;
background: #666;
}
.grid-inner {
display: grid;
gap: 30px;
justify-content: center;
grid-auto-columns: calc(33% - 15px);
}
.box {
padding: 30px;
background: white;
border: 1px solid black;
}
.box:nth-child(2) {
grid-column: 2;
}
.box:nth-child(3) {
grid-column: 3;
}
<section>
<div class="grid-inner">
<div class="box"></div>
</div>
</section>
<section>
<div class="grid-inner">
<div class="box"></div>
<div class="box"></div>
</div>
</section>
<section>
<div class="grid-inner">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</section>
<section>
<div class="grid-inner">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</section>
<section>
<div class="grid-inner">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</section>

How do I toggle visibility of an entire dynamic row (flex wrap)?

Current Behavior
I have the following basic structure:
<section id="containers">
<div class="box" id="box1">
<div class="collapsible"><h2>Box 1</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box2">
<div class="collapsible"><h2>Box 2</h2></div>
<div class="content">Content</div>
</div>
<!-- ... dozens of .boxes ... -->
</section>
#containers is .display: flex; flex-wrap: wrap, so the number of boxes on any one row is dynamic. This is an important feature that must be maintained.
Here's a minimal working example:
$(document).ready(function() {
$(".collapsible").click(function() {
$( this ).next().slideToggle();
});
});
#containers {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
.box {
min-width: 15em;
background: #888;
border: #555 1px solid;
overflow: hidden;
border-radius: 0.5em;
}
.collapsible {
background: #ccc;
cursor: pointer;
}
.collapsible h2 {
margin: 0;
margin-left: 16px;
font-size: 2rem;
}
.collapsible:hover {
background: #aaf;
}
.content {
margin: 0.5em;
margin-left: 16px;
display: none; /* Initially collapsed */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<p id="status"></p>
<section id="containers">
<div class="box" id="box1">
<div class="collapsible"><h2>Box 1</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box2">
<div class="collapsible"><h2>Box 2</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box3">
<div class="collapsible"><h2>Box 3</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box4">
<div class="collapsible"><h2>Box 4</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box5">
<div class="collapsible"><h2>Box 5</h2></div>
<div class="content">Content</div>
</div>
</section>
</body>
I can easily use .slideToggle() to toggle visibility of a sibling (.content) underneath one of the clickable .collapsible divs:
$(".collapsible").click(function() {
$( this ).next().slideToggle();
});
Desired Behavior and Remarks
What I'd like is, on click of any .collapsible div in a row, the entire row will be toggled. That is, every .content div on the same horizontal row as displayed in the current viewport.
This must handle rows with dynamic number of columns, including viewport resizing. I'm flexible on the precise behavior, though.
Is this possible? And how much will it hurt?🙂 Changes to the document structure (such as adding some sort of row container) are OK, and I don't mind using some JS/jQuery code of course. The main thing I can't do is hard code the number of columns, as I need my site to remain responsive on vertical phones and fullscreen desktop browsers.
Maybe the jQuery slideToggle() function is not the best method.
Since a row will be the same height , you may look at a method to set size from 0 to another value. anybox resized will stretch other boxes on the same row.
here an example of the idea, setting a max-height from 0 to 200px and a transition.
it toggles a class.
$(document).ready(function() {
$(".collapsible").click(function() {
this.classList.toggle('slide');// plain javascript to toggle a class
});
});
*{box-sizing:border-box}
#containers {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
.box {
min-width: 15em;
background: #888;
border: #555 1px solid;
overflow: hidden;
border-radius: 0.5em;
}
.collapsible {
background: #ccc;
cursor: pointer;
}
.collapsible h2 {
margin: 0;
margin-left: 16px;
font-size: 2rem;
}
p{margin-top:0;}
.collapsible:hover {
background: #aaf;
}
.content {
margin:0 0.5em;
margin-left: 16px;
max-height:0; /* Initially collapsed */
transition:0.5s
}
.slide + .content{max-height:400px;/* which one got the class*/ color:darkred}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<p id="status"></p>
<section id="containers">
<div class="box" id="box1">
<div class="collapsible"><h2>Box 1</h2></div>
<div class="content"><p>Content</p></div>
</div>
<div class="box" id="box2">
<div class="collapsible"><h2>Box 2</h2></div>
<div class="content"><p>Content</p><p>Content</p></div>
</div>
<div class="box" id="box3">
<div class="collapsible"><h2>Box 3</h2></div>
<div class="content"><p>Content</p></div>
</div>
<div class="box" id="box4">
<div class="collapsible"><h2>Box 4</h2></div>
<div class="content"><p>Content</p><p>Content</p><p>Content</p></div>
</div>
<div class="box" id="box5">
<div class="collapsible"><h2>Box 5</h2></div>
<div class="content"><p>Content</p></div>
</div>
</section>
</body>
What you are missing here , is to set the height of the row to the height of the taller box, unless they will all be the same height.
For this, you can look for every box at the same top offset that the one clicked, and look for the tallest innercontent of the .contents and use this height .
Here comes the idea looking where each are standing and resets a max-height rule, you can inspire from too:
// defaut : supposed to be with no class 'slide' set on html elements
$(document).ready(function () {
let boxes = document.querySelectorAll(".collapsible");
let contents = document.querySelectorAll(".content");
$(".collapsible").click(function (event) {
let arrayContent = [];//reset
let hide=false;
for (i = 0; i < contents.length; i++) {
contents[i].style.maxHeight = "min-content";
let index = i;
let heightC = contents[i].offsetTop;
let boxOffset = contents[i].parentNode.offsetTop + 1;
// a few infos .add/remove what is needed
arrayContent.push({
index,
heightC,
boxOffset
});
contents[i].setAttribute("style", "");// resets inline style
}
let rowOffset = this.offsetTop;
if(this.classList.contains('slide')) {
hide=true;
}
let classState = this.classList;
arrayContent.forEach(function (obj) {
if (obj.boxOffset == rowOffset) {
if(hide == true) boxes[obj.index].classList.add('slide');/* reset needed if window resized => rows reorganized ? */
boxes[obj.index].classList.toggle("slide");
} else {
boxes[obj.index].classList.remove("slide");
}
});
});
});
* {
box-sizing: border-box
}
#containers {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
.box {
min-width: 15em;
background: #888;
border: #555 1px solid;
overflow: hidden;
border-radius: 0.5em;
}
.collapsible {
background: #ccc;
cursor: pointer;
}
.collapsible h2 {
margin: 0;
margin-left: 16px;
font-size: 2rem;
}
p {
margin-top: 0;
}
.collapsible:hover {
background: #aaf;
}
.content {
margin: 0 0.5em;
margin-left: 16px;
max-height: 0;
/* Initially collapsed */
transition: max-height 0.5s!important
}
.slide~.content {
max-height: 400px;
/* which one got the class*/
color: darkred;
}
.collapsible:before {
content: attr(class)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<p id="status"></p>
<section id="containers">
<div class="box" id="box1">
<div class="collapsible">
<h2>Box 1</h2>
</div>
<div class="content">
<p>Content</p>
</div>
</div>
<div class="box" id="box2">
<div class="collapsible">
<h2>Box 2</h2>
</div>
<div class="content">
<p>Content</p>
<p>Content</p>
</div>
</div>
<div class="box" id="box3">
<div class="collapsible">
<h2>Box 3</h2>
</div>
<div class="content">
<p>Content</p>
</div>
</div>
<div class="box" id="box4">
<div class="collapsible">
<h2>Box 4</h2>
</div>
<div class="content">
<p>Content</p>
<p>Content</p>
<p>Content</p>
</div>
</div>
<div class="box" id="box5">
<div class="collapsible">
<h2>Box 5</h2>
</div>
<div class="content">
<p>Content</p>
</div>
</div>
</section>
</body>

Avoid vertical scrollbar shift in container

In html, I have a panel with a fixed height which contains cards. It can contain one card or many cards. Hence, because the panel has a fixed height, it can be needed to have a scrollbar displayed in order to visualize all cards. This works properly with the property overflow: auto.
However, when the scrollbar is displayed, cards are shift. I would like to avoid that or at least hide this shift with a trick. I checked a lot of similar questions that suggests to use padding-left: calc(100vw - 100%); but it did not work since it is not the body scrollbar. The width of the card needs to be responsive according to the container's width.
Something that could work is to set the overflow: overlay and add a padding-right. However, this is not a standard and not compatible with firefox.
Here, you can find a reproduce example:
let flag = true;
const setHeight = () => {
if (flag) {
document.getElementById('container').style.setProperty('height', '100%');
} else {
document.getElementById('container').style.removeProperty('height');
}
flag = !flag;
};
document.getElementById('button').addEventListener('click', setHeight);
setHeight();
.panel-container {
height: 300px;
width: 510px;
padding: 8px 20px 0;
background-color: blue;
overflow: auto;
}
.card {
height: 86px;
width: 100%;
background-color: grey;
border-radius: 3px;
border: 1px solid red;
margin-bottom: 10px;
cursor: pointer;
}
.scrollbar::-webkit-scrollbar-track {
width: 14px;
}
.scrollbar::-webkit-scrollbar-thumb {
border-radius: 8px;
border: 4px solid green;
}
.scrollbar::-webkit-scrollbar-corner {
background-color: transparent;
}
.scrollbar::-webkit-scrollbar {
width: 8px;
height: 8px;
}
<button id="button">With/Without overflow</button>
<div id="container" class="panel-container scrollbar">
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
</div>
In fact, it was quite simple. Just play with the margin and set the overflow to scroll.
let flag = true;
const setHeight = () => {
if (flag) {
document.getElementById('container').style.setProperty('height', '100%');
} else {
document.getElementById('container').style.removeProperty('height');
}
flag = !flag;
};
document.getElementById('button').addEventListener('click', setHeight);
setHeight();
.panel-container {
height: 300px;
width: 510px;
padding: 8px 12px 0 20px;
background-color: blue;
overflow: scroll;
}
.card {
height: 86px;
width: 100%;
background-color: grey;
border-radius: 3px;
border: 1px solid red;
margin-bottom: 10px;
cursor: pointer;
}
.scrollbar::-webkit-scrollbar-track {
width: 14px;
}
.scrollbar::-webkit-scrollbar-thumb {
border-radius: 8px;
border: 4px solid green;
}
.scrollbar::-webkit-scrollbar-corner {
background-color: transparent;
}
.scrollbar::-webkit-scrollbar {
width: 8px;
height: 8px;
}
<button id="button">With/Without overflow</button>
<div id="container" class="panel-container scrollbar">
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
<div class="card">
<div class="card-left-container"></div>
<div class="card-middle-container"></div>
<div class="card-right-container"></div>
</div>
</div>

Make progress bars responsive

I have these progress bars which are suppose to work as ratings and they look good:
I have applied some CSS and I change their width with JavaScript by reading values from text files.
But are not responsive at all and whenever the window is resized:
HTML:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<div class="second-part">
<div class="row">
<div class="side">
<div>5 stars</div>
</div>
<div class="middle">
<div class="bar-container">
<div class="bar11" style="width: 10% ; height: 18px; background-color: gold;"></div>
</div>
</div>
<div class="side right">
<div class="p11">150</div>
</div>
<div class="side">
<div>4 stars</div>
</div>
<div class="middle">
<div class="bar-container">
<div class="bar12" style="width: 10% ; height: 18px; background-color: gold;"></div>
</div>
</div>
<div class="side right">
<div class="p12">63</div>
</div>
<div class="side">
<div>3 stars</div>
</div>
<div class="middle">
<div class="bar-container">
<div class="bar13" style="width: 10% ; height: 18px; background-color: gold;"></div>
</div>
</div>
<div class="side right">
<div class="p13">15</div>
</div>
<div class="side">
<div>2 stars</div>
</div>
<div class="middle">
<div class="bar-container">
<div class="bar14" style="width: 10% ; height: 18px; background-color: gold;"></div>
</div>
</div>
<div class="side right">
<div class="p14">6</div>
</div>
<div class="side">
<div>1 star</div>
</div>
<div class="middle">
<div class="bar-container">
<div class="bar15" style="width: 10% ; height: 18px; background-color: gold;"></div>
</div>
</div>
<div class="side right">
<div class="p15">20</div>
</div>
</div>
</div>
CSS:
* {
box-sizing: border-box;
}
/* Three column layout */
.side {
float: left;
width: 15%;
margin-top:10px;
}
.middle {
margin-top:10px;
float: left;
width: 70%;
}
/* Place text to the right */
.right {
text-align: left;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
/* The bar container */
.bar-container {
width: 90%;
background-color: #f1f1f1;
text-align: center;
color: white;
}
/* Responsive layout - make the columns stack on top of each other instead of next to each other */
#media (max-width: 400px) {
.side, .middle {
width: 100%;
}
.right {
display: none;
}
}
JavaScript to change progress bar width:
var par1 = 4;
for(var i = 10; i < 16; i++) {
$('.p' + (i+1)).text(table[0][par1]);
$('.bar' + (i+1)).css("width", table[0][par1]);
par1++;
}
How could I make it more responsive? Thank you in advance!
I recommend using css flexbox, so the items wrap instead of overlap when the page is resized. You could use media queries with this to adjust the size of the items and container so they don't overlap/wrap. This site has a good explanation of flexbox: A Complete Guide to Flexbox.

jQuery to clean flexbox structure from empty columns and rows

I am creating a jQuery to optimize table structure by removing all the extra rows and columns that:
a) contain less than 2 child elements
b) contain duplicate container (.column can't have child .column, .row can't have child .row)
I still didn't get it working, it runs in 6 steps (visible in the comments).
What is necessary to turn the #example into #solution?
var selection;
//1. Select all rows and columns
selection = $('#example').find('.row, .column');
//2. Deselect rows and columns with more than 1 child
selection = selection.not('.row:has(div:nth-of-type(2)), .column:has(div:nth-of-type(2))');
//3. Deselect rows and columns that contain cells
selection = selection.not('.row:has(.cell:nth-of-type(1)), .column:has(.cell:nth-of-type(1))');
//4. Remove redundant divs
console.log(selection);
//selection.css('border', '1px yellow solid');//paint them yellow (for testing)
selection.children().first().unwrap();
//5. Select duplicate rows and columns
selection = $('#example').find('.row:has(.row), .column:has(.column)');
//6. Remove redundant divs since first removal
selection.children().first().unwrap();
.grid {
display: flex;
min-height: 5px;
}
.row {
display: flex;
flex-grow: 1;
border: 1px solid red;
}
.cell {
flex-grow: 1;
flex-basis: 20px;
border: 1px solid green;
}
.column {
display: flex;
flex-grow: 1;
flex-direction: column;
border: 1px solid blue;
}
.row,
.column,
.cell {
margin: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<span>Example</span>
<div id="example" class="grid">
<div class="column">
<div class="row">
<div class="column">
<div class="row">
<div class="column">
<div class="cell">
</div>
</div>
</div>
</div>
<div class="column">
<div class="row">
<div class="cell">
</div>
<div class="cell">
</div>
</div>
</div>
</div>
</div>
</div>
<span>Solution</span>
<div id="solution" class="grid">
<div class="row">
<div class="cell">
</div>
<div class="cell">
</div>
<div class="cell">
</div>
</div>
</div>
Based on the formula you have given, try this demo
$('#example').find('.column').each(function(){
$(this).find(".column").each(function(){
$(this).unwrap();
});
if ($(this).children().size() < 2 && $(this).find(".cell").size() == 0 )
{
$(this).remove();
}
});
$('#example').find('.row').each(function(){
$(this).find(".row").each(function(){
$(this).unwrap();
});
if ($(this).children().size() < 2 && $(this).find(".cell").size() == 0 )
{
$(this).remove();
}
});
This is a solution to updated version of the constraints, constraint A was reduced to minimum to provide an even better result (it is possible to reduce this example to bare minimum of one row).
//Constraint A
$('#example').find('.row, .column').each(function() {
if ($(this).children().size() < 2) {
$(this).children().first().unwrap();
}
});
//Constraint B
$('#example').find('.column').each(function() {
if ($(this).parent().hasClass('column')) {
$(this).children().first().unwrap();
}
});
$('#example').find('.row').each(function() {
if ($(this).parent().hasClass('row')) {
$(this).children().first().unwrap();
}
});
.row {
display: flex;
flex-grow: 1;
border: 1px solid red;
}
.cell {
flex-grow: 1;
flex-basis: 20px;
border: 1px solid green;
}
.column {
display: flex;
flex-grow: 1;
flex-direction: column;
border: 1px solid blue;
}
.row,
.column,
.cell {
margin: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<span>Solution</span>
<div id="example" class="row">
<div class="column">
<div class="row">
<div class="column">
<div class="row">
<div class="column">
<div class="cell">
</div>
</div>
</div>
</div>
<div class="column">
<div class="row">
<div class="cell">
</div>
<div class="cell">
</div>
</div>
</div>
</div>
</div>
</div>

Categories