Using Grid to layer items over each other - css

I am using absolute positioning to layer div one, two, three (and cover main). Would it be possible to achieve the same with CSS grid?
div.main is always displayed
div one, two, three will be shown when needed
Update: Toggle button added for better visualisation
const div = document.querySelector('div.content');
document.querySelector('button').addEventListener('click', () => {
const on = document.querySelector('.on');
on?.classList.remove('on');
(on?.nextElementSibling || div.firstElementChild).classList.add('on');
});
* {
box-sizing: border-box;
}
button {
padding: 0.5em;
margin-bottom: 1em;
}
.content {
width: 15em;
height: 8em;
position: relative;
margin: 0;
padding: 0;
border: 1px solid #aaa;
}
.main {
height: 100%;
background: #eee;
padding: 0.5em;
}
.one,
.two,
.three {
display: none;
margin: 0;
padding: 2em;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 3;
}
.one.on,
.two.on,
.three.on {
display: block;
}
.one {
background: #fef8;
}
.two {
background: #fec8;
}
.three {
background: #cdc8;
}
<button>Toggle</button>
<div class="content">
<div class="main on">This is main</div>
<div class="one">This is one</div>
<div class="two">This is two</div>
<div class="three">This is three</div>
</div>

Assuming that the div just need to stack on each other, perhaps a simple implement would be setting content a grid of a single cell, and have all the div placed in grid-area: 1/1/1/1.
Example: (with a simple display toggle)
const btn = document.querySelector("button");
const divs = document.querySelectorAll("div > div");
let i = 1;
btn.addEventListener("click", () => {
if (i === 4) {
divs.forEach((div) => div.classList.remove("on"));
i = 1;
return;
}
divs[i - 1].classList.toggle("on");
divs[i].classList.toggle("on");
i++;
});
.content {
width: 15em;
height: 20em;
margin: 0;
padding: 0;
border: 1px solid blue;
display: grid;
}
.main {
border: 1px solid red;
grid-area: 1/1/1/1;
}
.one,
.two,
.three {
display: none;
margin: 0;
padding: 1em;
z-index: 3;
border: 1px solid green;
grid-area: 1/1/1/1;
}
.one.on,
.two.on,
.three.on {
display: block;
}
button {
padding: 6px;
margin-bottom: 1em;
}
.one {
background-color: rgba(100, 149, 237, 0.25);
}
.two {
background-color: rgba(34, 139, 34, 0.25);
}
.three {
background-color: rgba(255, 140, 0, 0.25);
}
<button>Toggle</button>
<div class="content">
<div class="main">This is main</div>
<div class="one">This is one</div>
<div class="two">This is two.</div>
<div class="three">This is three.</div>
</div>

Related

How to animate scaling of div with gridlayout smoothly

I have a which contains a gridlayout with some cells. When the div is shown or hidden it should scale gradually over time. Currently when showing, the div is initially sized to fit the contents and then scales. When hidden it is immediately hidden unless padding is set. Then it is immediately resized to the size of the padding.
Example is shown below. How to adapt the styling in such that the div resizes smoothly and text stays in place (clips and does not wrap)
function toggle() {
if (document.getElementsByClassName("ovdInfobox")[0].classList.contains("ovdInfobox--visible")) {
document.getElementsByClassName("ovdInfobox")[0].classList.remove("ovdInfobox--visible")
console.log('remove');
} else {
document.getElementsByClassName("ovdInfobox")[0].classList.add("ovdInfobox--visible")
console.log('add');
}
}
.ovdInfobox {
display: grid;
grid: 40px auto / auto auto;
z-index: 1;
position: absolute;
top: 50px;
width: 0;
height: 0;
min-width: 0;
min-height: 0;
overflow: hidden;
padding: 0;
border: 0;
background: rgba(255, 255, 255, 0.98);
border-radius: 4px;
font-family: inherit;
font-size: inherit;
line-height: inherit;
transition: all 4.2s ease-in-out;
background: green;
}
.ovdInfobox--visible {
width: unset;
height: unset;
min-width: 300px;
border: 1px solid #d1d1d1;
/* padding: 15px 15px 15px 15px;*/
}
.ovdInfobox__header {
grid-column-start: span 2;
color: #c20063;
font-size: 18px;
font-weight: normal;
}
.ovdInfobox__label {
font-weight: bold;
}
.ovdInfobox__data {}
<div>
<button onclick="toggle()">
Click Me!
</button>
<div class="ovdInfobox ovdInfobox--visible" onCLick="toggle()">
<div class="ovdInfobox__header">Details</div>
<div class="ovdInfobox__label">
label
</div>
<div class="ovdInfobox__data">
data
</div>
<div class="ovdInfobox__label">
label
</div>
<div class="ovdInfobox__data">
data
</div>
</div>
</div>
New day, fresh start, fresh mind.
Changed class .ovdInfobox and .ovdInfobox--visible by replacing width, height, min-width and min-height by max-width and max-height. Resizing now works as expected.
function toggle() {
if (document.getElementsByClassName("ovdInfobox")[0].classList.contains("ovdInfobox--visible")) {
document.getElementsByClassName("ovdInfobox")[0].classList.remove("ovdInfobox--visible")
console.log('remove');
} else {
document.getElementsByClassName("ovdInfobox")[0].classList.add("ovdInfobox--visible")
console.log('add');
}
}
.ovdInfobox {
display: grid;
grid: 40px auto / auto auto;
column-gap:10px ;
row-gap: 5px;
z-index: 1;
position: absolute;
top: 50px;
max-width: 0;
max-height: 0;
overflow: hidden;
padding: 0;
border: 0;
background: rgba(255, 255, 255, 0.98);
border-radius: 4px;
font-family: inherit;
font-size: inherit;
line-height: inherit;
transition: all 4.2s ease-in-out;
background: green;
}
.ovdInfobox--visible {
max-width: 300px;
max-height: 200px;
border: 1px solid #d1d1d1;
padding: 15px 15px 15px 15px;
}
.ovdInfobox__header {
grid-column-start: span 2;
color: #c20063;
font-size: 18px;
font-weight: normal;
}
.ovdInfobox__label {
font-weight: bold;
}
.ovdInfobox__data {}
<div>
<button onclick="toggle()">
Click Me!
</button>
<div class="ovdInfobox ovdInfobox--visible" onCLick="toggle()">
<div class="ovdInfobox__header">Details</div>
<div class="ovdInfobox__label">
label
</div>
<div class="ovdInfobox__data">
data
</div>
<div class="ovdInfobox__label">
label
</div>
<div class="ovdInfobox__data">
data
</div>
</div>
</div>

Css select child elements from parent div

I have this html:
<div class="banner-right">
<img src="images/circle-icon.png" alt="">
<p class="rotate mt-40">和小物</p>
<p class="rotate mta">和小物</p>
<!-- If we need pagination -->
<div class="swiper-pagination"></div>
</div>
I want to select the first and last p element so that I can increase it's font size to 20px and 15px
My scss code:
.banner-right {
width: 122px;
max-width: 100%;
display: flex;
align-items: center;
flex-direction: column;
padding-top: 15px;
margin: 0 auto;
img {
width: 25px;
}
.swiper-pagination {
position: relative;
}
.swiper-pagination-bullet {
border-radius: 0;
margin-right: 5px;
background-color: transparent;
border: 1px solid #000;
&.swiper-pagination-bullet-active {
background-color: #000;
outline: 0;
}
}
&:first-of-type {
p {
font-size: 20px;
}
}
&:last-of-type {
p {
font-size: 15px;
}
}
}
But doesn't work :(
At the moment, your Sass will compile to:
.banner-right:first-of-type p
But you want it to be:
.banner-right p:first-of-type
So change your Sass as follows:
.banner-right {
p:first-of-type {
font-size: 20px;
}
p:last-of-type {
font-size: 15px;
}
}

Flexbox: Have item expand to fill row

I'm trying to modify my layout on mobile using flexbox and running into an issue. I would like for the middle box (2) to be rendered on its own line at 100% width on mobile. I used order: 1 to move the box to the end, but now I can't figure out how to display the box at full width.
.left, .middle, .right {
background-color: rgba(84, 97, 156, 0.2);
height: 100px;
padding: 20px;
margin: 5px;
border-radius: 4px;
color: rgb(84, 97, 156);
}
.right {
text-align: right;
flex-grow: 1;
}
.middle {
text-align: center;
order: 1;
}
.table-row {
display: flex;
}
<div class="table-row">
<div class="left">1</div>
<div class="middle">2</div>
<div class="right">3</div>
</div>
Here you can resize the viewable area https://jsfiddle.net/mtukb38r/
.table-row {
display: flex;
}
.left,
.middle,
.right {
background-color: rgba(84, 97, 156, 0.2);
height: 100px;
padding: 20px;
margin: 5px;
border-radius: 4px;
color: rgb(84, 97, 156);
}
.right {
text-align: right;
flex-grow: 1;
}
.middle {
text-align: center;
}
#media only screen and (max-width: 600px) {
.table-row {
flex-wrap: wrap;
}
.middle {
text-align: center;
order: 1;
width: 100%;
}
}
<div class="table-row">
<div class="left">1</div>
<div class="middle">2</div>
<div class="right">3</div>
</div>
basically it's this on desktop
.table-row {
display: flex;
}
.left,
.middle,
.right {
background-color: rgba(84, 97, 156, 0.2);
height: 100px;
padding: 20px;
margin: 5px;
border-radius: 4px;
color: rgb(84, 97, 156);
}
.right {
text-align: right;
flex-grow: 1;
}
.middle {
text-align: center;
}
<div class="table-row">
<div class="left">1</div>
<div class="middle">2</div>
<div class="right">3</div>
</div>
and this on mobile
.table-row {
display: flex;
}
.left,
.middle,
.right {
background-color: rgba(84, 97, 156, 0.2);
height: 100px;
padding: 20px;
margin: 5px;
border-radius: 4px;
color: rgb(84, 97, 156);
}
.right {
text-align: right;
flex-grow: 1;
}
.middle {
text-align: center;
}
.table-row {
flex-wrap: wrap;
}
.middle {
text-align: center;
order: 1;
width: 100%;
}
<div class="table-row">
<div class="left">1</div>
<div class="middle">2</div>
<div class="right">3</div>
</div>

Getting correct grid with Flexbox

Can someone point me out how can I get a grid with Flexbox that is similar to the picture below. I have green column already done but have problem doing red section.
The problem is that I need to have an access to Flex Order just re-order it on mobile resolutions.
What I have already:
JSFiddle
HTML
* {
box-sizing: border-box;
}
main,
div {
display: flex;
padding: 1rem;
}
.desktop {
flex-direction: column;
flex-wrap: wrap;
height: 400px;
width: 100%;
}
.desktop div {
flex: 1;
}
div.orange {
background-color: #FFAD77;
width: 30%;
flex: 0 0 50%;
}
div.yellow {
flex: 0 0 100%;
width: 40%;
background-color: #FFE377;
}
div.purple {
flex: 0 0 50%;
width: 30%;
background-color: #FF77C8;
}
div.green {
background-color: green;
width: 30%;
}
#media(max-width: 480px) {
.desktop div {
flex: 1;
width: 100%;
}
div.orange {
order: 1;
}
div.yellow {
order: 2;
}
div.purple {
order: 3;
}
div.green {
order: 2;
}
}
<div class="desktop">
<div class="yellow">lorem1</div>
<div class="orange">lorem2</div>
<div class="purple">lorem3</div>
<div class="green">lorem4</div>
</div>
Please adjust the width, remove border and other things are per your requirement.
.redouter {
height: 200px;
border: 1px solid green;
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.red {
background: red;
width: 50%;
min-height: 20px;
text-align: center;
color: white;
font-size: 30px;
}
.one {
border: 2px solid white;
}
.two {
border: 5px solid white;
min-height: 150px;
}
.three {
min-height: 144px;
border: 3px solid white;
}
.four {
min-height: 10px;
border: 3px solid white;
}
#media(max-width: 480px) {
.redouter {
height: 100%;
}
.red {
flex: 1;
width: 100%;
}
.one {
order: 1;
}
.two {
order: 2;
}
.three {
order: 3;
}
.four {
order: 2;
}
}
.desktop {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 300px;
width: 100%;
}
.yellow,
.green,
.purple,
.orange {
flex: 1;
}
div.orange {
background-color: #FFAD77;
width: 30%;
flex: 0 0 50%;
}
div.yellow {
flex: 0 0 100%;
width: 40%;
background-color: #FFE377;
}
div.purple {
flex: 0 0 50%;
width: 30%;
background-color: #FF77C8;
}
div.green {
background-color: green;
width: 30%;
}
#media(max-width: 480px) {
.desktop div {
flex: 1;
width: 100%;
}
div[orange] {
order: -1;
flex: 2;
}
div[yellow] {
flex: 5;
}
div[purple] {
flex: 1;
}
div[purple] {
flex: 6;
}
}
<div class="desktop">
<div class="yellow">lorem 1</div>
<div class="orange">lorem 2</div>
<div class="purple">lorem 3</div>
<div class="green">lorem 4</div>
</div>
<div class="redouter">
<div class="red one">1</div>
<div class="red two">2</div>
<div class="red three">3</div>
<div class="red four">4</div>
</div>

CSS Grid Layout Strange Behavior on Window Resize

Chrome Version 60.0.3112.78 (Official Build) (64-bit) in Windows 7
I'm exploring CSS Grid layout and have come across an odd issue in Chrome (works fine in Firefox). I've created a simple registration form that I want to center horizontally and vertically on the page.
I use three nested grids to structure my layout.
html {
height: 100%;
}
body {
font-family: 'Rubik', sans-serif;
margin: 0;
padding: 0;
background: #aaffff;
height: 100%;
}
#root {
height: 100%;
}
button,
input,
label {
font-family: 'Rubik', sans-serif;
font-weight: 600;
}
label {
display: inline-block;
text-align: left;
}
.formGroup {
display: inline-block;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
a:link {
text-decoration: none;
color: inherit;
}
a:hover {
text-decoration: underline;
}
*:focus {
outline-width: 3px;
outline-color: rgba(66, 66, 66, 0.7);
outline-style: dashed;
outline-offset: 3px;
}
.Input {
color: #333;
border: none;
height: 2em;
padding: 5px 10px;
display: block;
/* width: 100%; */
}
.Input:focus {
outline-width: 3px;
outline-color: rgba(66, 66, 66, 0.7);
outline-style: dashed;
outline-offset: 3px;
}
.Button {
display: inline-block;
font-weight: 800;
text-align: center;
white-space: nowrap;
vertical-align: middle;
padding: 20px 40px;
border-radius: 4px;
border: none;
background: none;
position: relative;
text-transform: uppercase;
margin: 15px 30px;
}
.Button.primary {
background: #0000ff;
box-shadow: 0 9px #000088;
color: #fff;
}
.Button.primary:hover {
top: 5px;
box-shadow: 0 4px #000088;
}
.Button.primary:active {
top: 9px;
box-shadow: none;
}
.Button.primary:focus {
outline-width: 3px;
outline-color: rgba(0, 0, 255, 0.7);
outline-style: dashed;
outline-offset: 3px;
}
.RegistrationForm-container {
display: grid;
grid-template-columns: 3% auto 3%;
grid-template-rows: 100px 25% auto 25%;
}
.RegistrationForm-container .copy {
grid-column-start: 2;
grid-row-start: 2;
}
.RegistrationForm-container form {
grid-column-start: 2;
grid-column-end: 3;
grid-row-start: 3;
display: grid;
grid-template-columns: 1% auto 1%;
grid-template-rows: 25px auto 25px;
}
.RegistrationForm-container form .inner {
grid-column-start: 2;
grid-column-end: 3;
grid-row-start: 2;
grid-row-end: 3;
display: grid;
grid-template-columns: 1% auto 1%;
grid-template-rows: 50px 50px;
}
.RegistrationForm-container form .inner .emailFormGroup {
grid-column-start: 2;
grid-row-start: 1;
margin: 0 auto;
}
.RegistrationForm-container form .inner .buttonFormGroup {
grid-column-start: 2;
grid-row-start: 2;
}
.App {
text-align: center;
height: 100%;
}
<div id="root">
<div class="App">
<div class="RegistrationForm-container">
<div class="copy">
<h1>Register</h1>
<p>
By registering, you agree to our
terms of use and privacy policy.
</p>
</div>
<form>
<div class="inner">
<div class="formGroup emailFormGroup">
<input
class="Input"
type="email"
placeholder="Email"
autocorrect="false"
/>
</div>
<div class="formGroup buttonFormGroup">
<button type="submit" class="Button primary">
Submit
</button>
</div>
</div>
</form>
</div>
</div>
</div>
While, my grid layout does succeed centering, it misbehaves when the window is resized. When the window is resized larger than the original load size, and then narrowed, a scrollbar appears and the input and button get stuck off to the right.
Only after clicking somewhere in the page or tabbing between the button, input, and terms of use link will it correct itself and snap back into vertical/horizontal centeredness.
Here are demonstrations of the behavior:
https://codepen.io/jdoyle/pen/qXadXJ
https://plnkr.co/edit/rzAAAsfgPVUfxxmXlqYa?p=preview
Looks like margin:auto in a grid does start to act pretty weird.
A way to get the effect you want but avoiding the bug would be to set
text-align: center;
on the emailFormGroup and then remove the display: block on email input.
https://codepen.io/anon/pen/YxGyeG

Resources