Brick Wall with Border-collapse Alternatives - html

I want containers in a brick wall pattern, see image. The borders should collapse into 1px (works for tables only). Tiles should change border color during interaction. I'm seeking cleanest solution. Things I've tried:
A single table: aligns the columns, ruining brick layout.
Each row as separate table: allows border-collapse within the row only.
Margin 1px with background color: won't collapse with floated or inline-block divs. (I read margin-collapse is for vertical space only.)
My best solution (not pictured): each row is separate table with border-collapse, border around half cells (not preferred), removed top borders of all cells, added border to top of top row. Container in the containers have 1px transparent border which becomes red when tile is highlighted. I lose space to this border. I chose transparent instead of 0px to keep it consistent. The half cells aren't interactive, they're just for layout. I wish they didn't have a border so it would have a toothy look on edge.
For tables I'm using divs with display:table etc. I was hoping not to resort to canvas yet, though at some point I will for overlaying robust graphics.

you may relay only on 2 borders or box-shadow to avoid interaction with the container.
example with box shadow :
* {
margin: 0;
box-sizing: border-box;
}
body {
height: 100vh;
display: flex;
}
article {
margin: 15px;
flex: 1;
display: grid;
grid-template-columns: repeat(9, 1fr);
border: 1px solid;
background: tomato;
}
div {
box-shadow: 1px 1px 0 1px;
grid-column: auto / span 2;
}
div:nth-child(10n),
div:nth-child(10n-9) {
grid-column: auto / span 1
}
<article>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</article>

Related

How do I make a honeycomb grid using CSS?

I need to create a honeycomb grid wherein the 9 honeycomb filled with red color should always be at center when the screen width changes.
More likely my goal is to have the same effect as background-size: cover / object-fit: cover but for container / elements, so the black honeycomb will just overflow to the screen if the width has become smaller therefore the red honeycomb will always be at center.
This is what I am currently using as basis but I can't seem to the background-size: cover effect + this example is using inline to, so as the width becomes smaller the rows just keeps adding which I want to avoid.
.main {
display: flex;
--s: 100px;
/* size */
--m: 4px;
/* margin */
--f: calc(1.732 * var(--s) + 4 * var(--m) - 1px);
}
.container {
font-size: 0;
/*disable white space between inline block element */
}
.container div {
width: var(--s);
margin: var(--m);
height: calc(var(--s)*1.1547);
display: inline-block;
font-size: initial;
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
background: red;
margin-bottom: calc(var(--m) - var(--s)*0.2885);
}
.container div:nth-child(odd) {
background: green;
}
.container::before {
content: "";
width: calc(var(--s)/2 + var(--m));
float: left;
height: 120%;
shape-outside: repeating-linear-gradient( #0000 0 calc(var(--f) - 3px), #000 0 var(--f));
}
<div class="main">
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
What you actually need is two rows of centered elements where the second row is slightly shifted. You don't need that complex code (which I made btw).
I have used 15 elements on the first container and 14 on the second one (minus one). You can add as many element as you want but you have to update the selector to correctly color your 9 elements.
.container {
overflow: hidden;
}
.container > div {
display: flex;
gap: 6px;
justify-content: center;
}
.container > div > div {
width: 80px;
aspect-ratio: 0.866;
flex-shrink: 0;
clip-path: polygon(0 25%,50% 0,100% 25%,100% 75%,50% 100%,0 75%);
background: black;
}
.container > div:last-child {
transform: translateY(calc(6px - 25%));
}
.container > div > div:nth-child(6),
.container > div > div:nth-child(7),
.container > div > div:nth-child(8),
.container > div > div:nth-child(9),
.container > div > div:nth-child(10) {
background: red;
}
.container > div:last-child > div:nth-child(10) {
background: black;
}
<div class="container">
<div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>

CSS make squared grid cells with uneven rows and columns [duplicate]

This question already has answers here:
CSS grid square layout [duplicate]
(4 answers)
Closed 2 months ago.
In HTML I create a grid container, and style it in the following way:
height: 95%;
display: grid;
grid-template-columns: repeat(8, auto);
I then fill my grid with divs styled in the following manner.
display: flex;
align-items: center;
justify-content: center;
width: 100%;
aspect-ratio: 1;
background-color: red;
position: relative;
As you can see the tiles are squared, but the grid 'cells' are rectangles. I would like to make the cells squared, so that the gap between tiles on different rows is no longer there.
You can use the gap property to define the gaps between the grid cells. Also make sure, you haven't set the align-content property to a value, that creates space between the rows.
.container {
height: 95%;
display: grid;
gap: 4px;
grid-template-columns: repeat(8, auto);
}
.container > div {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
aspect-ratio: 1;
background-color: red;
position: relative;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>

Using auto-fit, how do I make a 3-item grid that may have 1 or 3 columns but never 2 columns? [duplicate]

Looked into a few questions here but they don't quite solve what I'm looking for.
Say I have a website and I want. On desktop I want this:
This is easy. grid-template-columns: repeat(3, 33%) (basically)
On mobile, however, I want this
What I'm running into is happens before it flips to a single column:
I'm trying clamp(), minmax(), and all sorts of things but nothing ever works as I want. Yes, I can totally use a media query but I was hoping to create a truly fluid grid/flex layout using modern CSS like clamp, grid, minmax, etc so there wouldn't be a need for media queries for basic layout changes.
I know this doesn't work but as a starting point as requested here's a simple version of one of my 100 attempts :) In this version I was trying to use clamp to switch from a repeat(3) to repeat(1).
.wrapper {
display: grid;
gap: 15px;
grid-template-columns: repeat(clamp(1, calc(100% - 500px), 3), 33%);
}
.one {
background: red;
}
.two {
background: green;
}
.three {
background: blue;
}
<div class="wrapper">
<div class="item one"><h3>Example A</h3></div>
<div class="item two"><h3>Example Two</h3></div>
<div class="item three"><h3>Third Example</h3></div>
</div>
Full article with more generic rules: https://css-tricks.com/responsive-layouts-fewer-media-queries/
Here is an idea using max(0px, (400px - 100vw)*1000) inside flex-basis. This formula will eiter give 0px if 100vw (screen size) is bigger than 400px or a very big value in the opposite case giving each element a big flex-basis and create a wrapping. Simply adjust the 400px which play the role of #media (max-width:400px)
.container {
display:flex;
flex-wrap:wrap;
}
.container div {
height:100px;
border:2px solid;
background:red;
flex-basis:max(0px, (400px - 100vw)*1000);
flex-grow:1;
}
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
Using CSS grid it can be like below:
.container {
display:grid;
grid-template-columns:repeat(auto-fill,minmax(clamp(30%, (400px - 100vw)*1000, 100%),1fr));
grid-gap:5px;
}
.container div {
height:100px;
border:2px solid;
background:red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
A similar question where I am controling the maximum number of columns without media query: CSS grid - maximum number of columns without media queries
We can scale the above solution to consider more complex cases.
Example of moving from 6 to 3 to 1 column:
.container {
display:grid;
grid-template-columns:
repeat(auto-fill,
minmax(clamp(clamp(15%,(800px - 100vw)*1000, 30%), (400px - 100vw)*1000, 100%)
/* if(screen> 800px) 15% elseif(screen> 400px) 30% else 100% */
,1fr));
grid-gap:5px;
}
.container div {
height:100px;
border:2px solid;
background:red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
To understand the values consider the following ranges:
100%/7 100%/6 100%/5 100%/4 100%/3 100%/2 100%/1
14.3% 16.7% 20% 25% 33.3% 50% 100%
To get 6 columns we need a value in the range ]14.3% 16.7%] (I considered 15%)
To get 3 columns we need a value in the range ]25% 33.3%] (I considered 30%)
We simply avoid the edges to make sure we account for the gaps.
A more generic solution using CSS variables where I will add 0.1% to make sure the value is big enough to get the needed number of column and it can hold the gap.
Let's also add some dynamic coloration (related: How to change the color of <div> Element depending on its height or width?)
.container {
/* first breakpoint*/
--w1:800px;
--n1:6;
/* second breakpoint*/
--w2:400px;
--n2:3;
display:grid;
grid-template-columns:
repeat(auto-fill,
minmax(clamp(clamp(100%/(var(--n1) + 1) + 0.1%, (var(--w1) - 100vw)*1000,
100%/(var(--n2) + 1) + 0.1%), (var(--w2) - 100vw)*1000,
100%), 1fr));
grid-gap:5px;
margin:10px 0;
}
.container div {
height:100px;
border:2px solid;
background:
linear-gradient(blue 0 0) 0 /1% calc(var(--w2) - 100vw),
linear-gradient(green 0 0) 0 /1% calc(var(--w1) - 100vw),
red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:900px;--n1:8;--w2:500px;--n2:4;grid-gap:10px;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:600px;--n1:4;--n2:2;grid-gap:2vw;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
Using flexbox where we can have a different (probably wanted) behavior where the last item of a row will take all the free space:
.container {
/* first breakpoint*/
--w1:800px;
--n1:6;
/* second breakpoint*/
--w2:400px;
--n2:3;
display:flex;
flex-wrap:wrap;
margin:10px 0;
}
.container div {
height:100px;
border:2px solid;
margin:5px;
flex-basis:clamp(clamp(100%/(var(--n1) + 1) + 0.1% ,(var(--w1) - 100vw)*1000,
100%/(var(--n2) + 1) + 0.1%),(var(--w2) - 100vw)*1000,
100%);
flex-grow:1;
box-sizing:border-box;
background:
linear-gradient(blue 0 0) 0 /1% calc(var(--w2) - 100vw),
linear-gradient(green 0 0) 0 /1% calc(var(--w1) - 100vw),
red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:900px;--n1:8;--w2:500px;--n2:4;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:600px;--n1:4;--n2:2;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
You can achive this by using grid like this:
.btnContainer {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* here you set when the width should change to be moved to the next row, in this example, the divs will move when the screen reduces size and their width is less than 200px */
}
.btnCenter3 {
background-color: rgb(6, 198, 247);
height: 400px;
}
.btnCenter4 {
height: 400px;
background-color: rgb(196, 95, 1);
}
.btnCenter5 {
height: 400px;
background-color: rgb(192, 231, 19);
}
<div class="btnContainer">
<div class="btnCenter3"></div>
<div class="btnCenter4"></div>
<div class="btnCenter5"></div>
</div>
#Temani's answer is bonkers but great :). I needed to implement a similar thing for a 4 column layout (breaking to 2 cols then 1 col) but found that replacing the 15 and 30 percentage values for 25 and 50 didn't work. This seems to be related to the fact that the percentages need to take account of the grid gap, so #Temani's answer only really works because of the rounding 'error'. So a more robust (if even more bonkers) solution, based on a 4 col grid is:
:root {
--grid-gap: 10px;
--grid-gap-x2: calc(var(--grid-gap));
}
.container {
display:grid;
grid-gap: var(--grid-gap-x2);
grid-template-columns:
repeat(auto-fill, minmax(clamp(clamp(calc(25% - var(--grid-gap-x2)),(800px - 100vw)*1000, calc(50% - var(--grid-gap-x2))), (400px - 100vw)*1000, 100%)
/* if(screen> 800px) 25% elseif(screen> 400px) 50% else 100%. */
/* (Subtracting grid gap from either side of percentage width.) */
,1fr));
}

4x4 grid of squares that scale up to a maximum width

How should I edit the CSS and/or HTML so that these squares fit to a particular maximum width, while maintaining the 4x4 square structure? Right now, it resizes to the width of the browser window, but if the browser is stretched out across the screen, the squares are far too large and the height goes well beyond the height of my screen.
I've tried adding a container div and adding a max-width, but that does not seem to relate to the width of 4 squares next to each other, and changes the width of each square without adjusting the height evenly.
.w {
overflow: hidden;
}
section {
margin: -1%;
padding: 20px;
}
section div {
background: #CCC;
float: left;
height: 24vw;
margin: 1%;
width: 23%;
color:white;
}
<div id="playGrid" class="w">
<section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
</div>
How about, you know, CSS grid? You can use the width and height to adjust the whole shebang's size.
#playGrid {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
gap: 15px;
align-content: stretch;
width: 50vw;
height: 50vw;
}
#playGrid div {
background: #CCC;
color: white;
}
<div id="playGrid" class="w">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
<div>14</div>
<div>15</div>
<div>16</div>
</div>
You can leverage CSS Grid Layout to define your grid, and then bound the height and width of the section to 100vh:
#playGridSection {
display: grid;
grid-template-columns: repeat(4, 25%);
grid-template-rows: repeat(4, 25%);
height: 100vh;
width: 100vh;
margin-right: auto;
margin-left: auto;
}
section div {
background: #CCC;
color:white;
align-self: stretch;
justify-self: stretch;
margin: 1vh;
}
<div id="playGrid">
<section id="playGridSection">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
</div>
You may relay on flex and a pseudo to stretch your element to a square boxe.
Here is a basic example. (You should also clarify what kind of content should be standing inside and which kind of layout you need, so we can tune/update HTML(the content to put inside) & CSS according to your real expected result, it could be like a sudoku grid ? Responsive grid of squares within a responsive grid of squares )
body {margin:0;}
.w {}
section {
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
padding: 20px;
max-width: 100vmin;
margin: auto;
}
section div {
background: #CCC;
min-width: 21%;
/* cannot be more than 4 on a row */
flex-grow: 1;
/* stretch their width evenly */
margin: 1vmin;
}
section div:before {
/* note, you need to stretch only one per row and
the selector can be also : section div:nth-child(4n):before */
content: '';
padding-top: 100%;
/* stretch height using width as a reference (padding/margin units in % ) */
float: left;
/* let it on the side to add content .. aside */
}
<div id="playGrid" class="w">
<section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
</div>

CSS Grid Column Stretch to Fill Entire Row / Or Centered In Row? [duplicate]

This question already has answers here:
Aligning grid items across the entire row/column (like flex items can)
(3 answers)
Closed 4 years ago.
I have a basic grid setup as follows:
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(33rem, 1fr));
grid-gap: 1rem;
}
When the grid auto-breaks into new rows, I either want the elements on the new rows to take up a proportional amount of space or be centered so that they look nice.
For example, if I have 3 elements in one row, then I want each to take up 33% of the container space. But when the grid breaks and only 1 element is on the new row, I want that element to either take up 100% of the row width, or at least look centered -- which is contrary to the default behavior of placing the element all the way to the left and taking up only 1fr of space.
Similarly, if there are 2 elements on the new row, then each should take up 50% of the row space or the two together should look centered.
I don't know how many elements there will be in total. Ideally, the solution should work for a minimum of 1 up to an arbitrary number of elements.
If anyone has any ideas, please let me know. Thanks.
This is a job for flexbox, I don't think it will be easy to achieve with CSS grid:
.grid-container {
display: flex;
flex-wrap:wrap;
border:1px solid;
margin:2px;
}
.grid-container>div {
height: 50px;
background: red;
margin: .5rem;
flex: 1 1 calc(33% - 1rem);
}
<div class="grid-container">
<div></div>
<div></div>
<div></div>
</div>
<div class="grid-container">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="grid-container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
If you want the element to be centred simply do this:
.grid-container {
display: flex;
flex-wrap:wrap;
border:1px solid;
margin:2px;
justify-content:center;
}
.grid-container>div {
height: 50px;
background: red;
margin: .5rem;
flex: 0 1 calc(33% - 1rem); /*disable the flex-grow*/
}
<div class="grid-container">
<div></div>
<div></div>
<div></div>
</div>
<div class="grid-container">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="grid-container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>