Alternative to grid layout transitions - css

This is a very common type of animation - toggle a sidebar on/off:
document.querySelector('.toggle').addEventListener('click', e =>
document.body.classList.toggle('no-aside')
)
body {
display: grid;
grid-gap: 10px;
grid-template-columns: minmax(50px, 200px) auto;
grid-template-areas: "aside main";
margin: 0;
width: 100vw;
height: 100vh;
transition: grid-template-columns .25s;
}
body.no-aside {
grid-template-columns: 50px auto;
}
aside {
background: #111;
color: #fff;
}
main {
background: #ddd;
}
.toggle {
background: #111;
width: 40px;
height: 40px;
display: block;
position: relative;
}
.toggle i,
.toggle i::after,
.toggle i::before {
position: absolute;
width: 40px;
height: 4px;
border-radius: 4px;
transition: transform .15s;
background-color: #fff;
}
.toggle i {
top: 46%;
left: 18%;
display: block;
opacity: .5;
}
.toggle i::before {
top: -10px;
}
.toggle i::after {
bottom: -10px;
}
.toggle i::after,
.toggle i::before {
content: '';
display: block;
}
.toggle i::before {
transform: translate3d(-8px, 0, 0) rotate(-45deg) scale(0.7, 1);
}
.toggle i::after {
transform: translate3d(-8px, 0, 0) rotate(45deg) scale(0.7, 1);
}
.no-aside .toggle i::before,
.no-aside .toggle i::after {
transform: none;
}
<aside>
<a class="toggle">
<i></i>
</a>
</aside>
<main>
content
</main>
But it appears that the transitions for grid* properties are not yet implemented in browsers so it doesn't work with a grid layout.
Is there a way to achieve this with other properties, but still keep the grid layout? Everything I've tried, with width, left, margin etc. seems to leave a gap between the 2 grid items.

Grid is supposed to have 5 animatable properties:
grid-gap, grid-row-gap, grid-column-gap, grid-template-columns and grid-template-rows.
But as you said, browsers have not implemented it yet. Firefox and Edge can animate grid-gap, grid-row-gap and grid-column-gap, but not grid-template-columns or grid-template-rows. Chromium browsers can't animate any grid property at all.
A workaround for this particular case would be to set the transition as width on the aside, and have the template columns declared as min-content 1fr.
document.querySelector('.toggle').addEventListener('click', e =>
document.body.classList.toggle('no-aside')
)
body {
display: grid;
grid-gap: 10px;
grid-template-columns: min-content 1fr;
/*
alternatively, ridiculously uneven FR columns can work too, such as
grid-template-columns: 1fr 30fr;
*/
grid-template-areas: "aside main";
margin: 0;
width: 100vw;
height: 100vh;
}
body.no-aside aside{
width:50px;
}
aside {
width:200px;
background: #111;
color: #fff;
transition: width 1s;
}
main {
background: #ddd;
}
.toggle {
background: #111;
width: 40px;
height: 40px;
display: block;
position: relative;
}
.toggle i,
.toggle i::after,
.toggle i::before {
position: absolute;
width: 40px;
height: 4px;
border-radius: 4px;
transition: transform .15s;
background-color: #fff;
}
.toggle i {
top: 46%;
left: 18%;
display: block;
opacity: .5;
}
.toggle i::before {
top: -10px;
}
.toggle i::after {
bottom: -10px;
}
.toggle i::after,
.toggle i::before {
content: '';
display: block;
}
.toggle i::before {
transform: translate3d(-8px, 0, 0) rotate(-45deg) scale(0.7, 1);
}
.toggle i::after {
transform: translate3d(-8px, 0, 0) rotate(45deg) scale(0.7, 1);
}
.no-aside .toggle i::before,
.no-aside .toggle i::after {
transform: none;
}
<aside>
<a class="toggle">
<i></i>
</a>
</aside>
<main>
123123
</main>

Related

CSS Add offset / distort between multiple borders?

Sandbox link: https://codesandbox.io/s/charming-hermann-pcpcsy?file=/src/styles.module.css
I want to create multi sector element using css. I need 4 segments as shown below:
<div className={classes.loader}>
<section className={classes.loader_sector}></section>
<section className={classes.loader_sector}></section>
<section className={classes.loader_sector}></section>
<section className={classes.loader_sector}></section>
</div>
and here's my CSS:
.loader_sector {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
border: 0.8rem solid transparent;
}
.loader_sector:nth-child(1) {
border-top-color: #fff;
}
.loader_sector:nth-child(2) {
border-left-color: #fff;
}
.loader_sector:nth-child(3) {
border-right-color: #fff;
}
.loader_sector:nth-child(4) {
border-bottom-color: #fff;
}
but this keeps all this circles stick together:
I want some gap at junction of every sector. Can someone help me achieve the same?
Edit one:
As suggested in comments using margin-top left and right solves the problem, but the core issue still remains, when I rotate them, they start contracting: https://codesandbox.io/s/charming-hermann-pcpcsy?file=/src/styles.module.css
Here you go, you can play with border radius and gap between sections to make it pretty.
.Spinner {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: purple;
display: flex;
align-items: center;
justify-content: center;
}
.loader > * {
box-sizing: border-box;
}
.loader {
color: red;
position: relative;
height: 10rem;
width: 10rem;
text-align: center;
vertical-align: center;
animation: rotate 2s ease-in-out infinite;
}
.loader_sector {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
border: 0.8rem solid transparent;
mix-blend-mode: overlay;
pointer-events: none;
}
.loader_sector:nth-child(1) {
border-top-color: pink;
margin-top: -5px;
}
.loader_sector:nth-child(2) {
border-left-color: blue;
margin-left: -5px;
}
.loader_sector:nth-child(3) {
border-right-color: green;
margin-left: 5px;
}
.loader_sector:nth-child(4) {
border-bottom-color: yellow;
margin-top: 5px;
}
#keyframes rotate {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
<div class=Spinner>
<div class=loader>
<section class=loader_sector></section>
<section class=loader_sector></section>
<section class=loader_sector></section>
<section class=loader_sector></section>
</div>
</div>
Replace this css code in your css file, it will work.
.Spinner {
position: absolute;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
background-color: black;
display: flex;
align-items: center;
justify-content: center;
}
.loader > * {
box-sizing: border-box;
}
.loader {
/* background-color: white; */
position: relative;
height: 10rem;
width: 10rem;
border-radius: 50%;
}
.loader_sector {
position: absolute;
/* background-color: blue; */
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
border: 0.8rem solid transparent;
}
.loader_sector:nth-child(1) {
border-top-color: pink;
margin-top: -10px;
}
.loader_sector:nth-child(2) {
border-left-color: blue;
margin-left: -10px;
}
.loader_sector:nth-child(3) {
border-right-color: green;
margin-left: 10px;
}
.loader_sector:nth-child(4) {
border-bottom-color: yellow;
margin-top: 10px;
}

Setting A Hamburger Menu So That It Stretches Across The Entire Screen

Below is the code that I've used to create a responsive hamburger menu. I'd like to set the hamburger menu so that when opened it stretches (and is displayed) across the entire screen. I imagine that this would involve editing the CSS, which I have unsuccessfully tried doing.
If anyone has any ideas on how I could have the hamburger menu displayed across the entire screen, I'd appreciate you sharing your knowledge with me. Thank you.
.body {
background-color: white;
font-family: sans-serif;
}
.searchbar {
float: right;
}
.image {
text-align: center;
}
.setsumei {
margin-left: 20px;
margin-right: 20px;
}
.footer {
width: 100%;
height: 40px;
text-align: center;
border-top: 1px solid black;
position: absolute;
bottom: 0;
padding: 10px;
}
.page-wrap {
min-height: 100%;
margin-bottom: -40px;
}
.page-wrap:after {
content: "";
display: block;
}
.site-footer,
.page-wrap:after {
height: 20px;
}
.site-footer {
text-align: center;
border-top: 1px solid black;
padding: 10px;
}
*,
*:before,
*:after {
padding-left: 0;
margin: 0;
box-sizing: border-box;
}
ol,
ul {
list-style: none;
}
a {
text-decoration: none;
color: black;
}
.cp_cont {
height: auto;
}
/* menu */
.cp_offcm03 {
position: relative;
z-index: 5000;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: auto;
width: 100%;
height: auto;
padding-top: 0;
-webkit-transition: transform 0.3s ease-in;
transition: transform 0.3s ease-in;
text-align: center;
color: black;
background-color: white;
}
.cp_offcm03 nav,
.cp_offcm03 ul {
height: 100%;
}
.cp_offcm03 li {
display: inline-block;
margin-right: -6px;
}
.cp_offcm03 a {
display: block;
padding: 15px 45px;
margin-bottom: -5px;
-webkit-transition: background-color .3s ease-in;
transition: background-color .3s ease-in;
}
.cp_offcm03 a:hover {
background-color: lightgray;
}
/* menu toggle */
#cp_toggle03 {
display: none;
}
#cp_toggle03:checked~.cp_offcm03 {
-webkit-transform: translateX(0);
transform: translateX(0);
}
#cp_toggle03:checked~.cp_container {
-webkit-transform: translateX(0);
transform: translateX(0);
}
.cp_mobilebar {
display: none;
}
/* content */
.cp_container {
position: relative;
top: 0;
padding: 35px auto;
-webkit-transition: transform .3s ease-in;
transition: transform .3s ease-in;
}
.cp_content {
margin: 0 auto;
padding: 20px;
height: 65vh;
text-align: center;
}
#media (max-width: 1130px)and (min-width: 280px) {
/* menu */
.cp_offcm03 {
position: fixed;
left: -250px;
overflow-y: hidden;
width: 250px;
height: 100%;
padding-top: 40px;
color: black;
background-color: white;
z-index: 1000;
}
.cp_offcm03 nav {
background: white;
border-right: 0.5px solid lightgray;
margin-left: -210px;
}
.cp_offcm03 li {
display: block;
margin-right: 0;
}
.cp_offcm03 a {
padding: 20px;
}
/* menu toggle */
.cp_mobilebar {
display: block;
z-index: 2000;
position: relative;
top: 0;
left: 0;
padding: 0 25px;
width: 100%;
height: 40px;
background-color: white;
border-bottom: .05px solid lightgray;
}
.cp_menuicon {
display: block;
position: relative;
width: 25px;
height: 100%;
cursor: pointer;
-webkit-transition: transform .3s ease-in;
transition: transform .3s ease-in;
}
.cp_menuicon>span {
display: block;
position: absolute;
top: 55%;
margin-top: -0.3em;
width: 100%;
height: 0.2em;
border-radius: 1px;
background-color: black;
-webkit-transition: transform .3s ease;
transition: transform .3s ease;
}
.cp_menuicon>span:before,
.cp_menuicon>span:after {
content: "";
position: absolute;
width: 100%;
height: 100%;
border-radius: 1px;
background-color: black;
-webkit-transition: transform .3s ease-in;
transition: transform .3s ease-in;
}
.cp_menuicon>span:before {
-webkit-transform: translateY(-0.6em);
transform: translateY(-0.6em);
}
.cp_menuicon>span:after {
-webkit-transform: translateY(0.6em);
transform: translateY(0.6em);
}
#cp_toggle03:checked+.cp_mobilebar .cp_menuicon {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
#cp_toggle03:checked+.cp_mobilebar span:before,
#cp_toggle03:checked+.cp_mobilebar span:after {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
#cp_toggle03:checked~.cp_offcm03 {
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
#cp_toggle03:checked~.cp_container {
-webkit-transform: translateX(250px);
transform: translateX(250px);
}
input:checked~#h-menu_black {
display: block;
opacity: .6;
}
#h-menu_black {
display: none;
position: fixed;
z-index: 999;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: black;
opacity: 0;
transition: .7s ease-in-out;
}
/* content */
.cp_container {
top: 60px;
height: 92vh;
text-align: center;
}
.noscroll {
overflow: hidden;
position: fixed;
}
}
<div class="cp_cont">
<input id="cp_toggle03" type="checkbox" />
<div class="cp_mobilebar">
<label for="cp_toggle03" class="cp_menuicon">
<span></span>
</label>
</div>
<label id="h-menu_black" class="cp_toggle03" for="cp_menuicon"></label>
<div id="body" class="noscroll"></div>
<header class="cp_offcm03">
<nav>
<ul style="text-align: center; margin-left: 210px; overflow: hidden">
<li style="border-bottom: 1px solid lightgray">Home</li>
<li style="border-bottom: 1px solid lightgray">Blog</li>
<li style="border-bottom: 1px solid lightgray">About This Website</li>
<li style="border-bottom: 1px solid lightgray">Bibliography</li>
</ul>
</nav>
</header>
</div>
It's just a matter of adjusting the menu width and the translation dimension to match. Look into how you can use your browser's document inspector to find styles relevant to your goals.
FYI, you don't need vendor prefixes for transform or transition.
/* Scroll down... */
.body {
background-color: white;
font-family: sans-serif;
}
.searchbar {
float: right;
}
.image {
text-align: center;
}
.setsumei {
margin-left: 20px;
margin-right: 20px;
}
.footer {
width: 100%;
height: 40px;
text-align: center;
border-top: 1px solid black;
position: absolute;
bottom: 0;
padding: 10px;
}
.page-wrap {
min-height: 100%;
margin-bottom: -40px;
}
.page-wrap:after {
content: "";
display: block;
}
.site-footer,
.page-wrap:after {
height: 20px;
}
.site-footer {
text-align: center;
border-top: 1px solid black;
padding: 10px;
}
*,
*:before,
*:after {
padding-left: 0;
margin: 0;
box-sizing: border-box;
}
ol,
ul {
list-style: none;
}
a {
text-decoration: none;
color: black;
}
.cp_cont {
height: auto;
}
/* menu */
.cp_offcm03 {
position: relative;
z-index: 5000;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: auto;
width: 100%;
height: auto;
padding-top: 0;
transition: transform 0.3s ease-in;
text-align: center;
color: black;
background-color: white;
}
.cp_offcm03 nav,
.cp_offcm03 ul {
height: 100%;
}
.cp_offcm03 li {
display: inline-block;
margin-right: -6px;
}
.cp_offcm03 a {
display: block;
padding: 15px 45px;
margin-bottom: -5px;
transition: background-color .3s ease-in;
}
.cp_offcm03 a:hover {
background-color: lightgray;
}
/* menu toggle */
#cp_toggle03 {
display: none;
}
#cp_toggle03:checked~.cp_offcm03 {
transform: translateX(0);
}
#cp_toggle03:checked~.cp_container {
transform: translateX(0);
}
.cp_mobilebar {
display: none;
}
/* content */
.cp_container {
position: relative;
top: 0;
padding: 35px auto;
transition: transform .3s ease-in;
}
.cp_content {
margin: 0 auto;
padding: 20px;
height: 65vh;
text-align: center;
}
#media (max-width: 1130px)and (min-width: 280px) {
/* menu */
.cp_offcm03 {
position: fixed;
left: -100vw; /* <------------------------------------------------ HERE */
overflow-y: hidden;
width: 100vw; /* <------------------------------------------------ HERE */
height: 100%;
padding-top: 40px;
color: black;
background-color: white;
z-index: 1000;
}
.cp_offcm03 nav {
background: white;
border-right: 0.5px solid lightgray;
margin-left: -210px;
}
.cp_offcm03 li {
display: block;
margin-right: 0;
}
.cp_offcm03 a {
padding: 20px;
}
/* menu toggle */
.cp_mobilebar {
display: block;
z-index: 2000;
position: relative;
top: 0;
left: 0;
padding: 0 25px;
width: 100%;
height: 40px;
background-color: white;
border-bottom: .05px solid lightgray;
}
.cp_menuicon {
display: block;
position: relative;
width: 25px;
height: 100%;
cursor: pointer;
-webkit-transition: transform .3s ease-in;
transition: transform .3s ease-in;
}
.cp_menuicon>span {
display: block;
position: absolute;
top: 55%;
margin-top: -0.3em;
width: 100%;
height: 0.2em;
border-radius: 1px;
background-color: black;
-webkit-transition: transform .3s ease;
transition: transform .3s ease;
}
.cp_menuicon>span:before,
.cp_menuicon>span:after {
content: "";
position: absolute;
width: 100%;
height: 100%;
border-radius: 1px;
background-color: black;
-webkit-transition: transform .3s ease-in;
transition: transform .3s ease-in;
}
.cp_menuicon>span:before {
-webkit-transform: translateY(-0.6em);
transform: translateY(-0.6em);
}
.cp_menuicon>span:after {
-webkit-transform: translateY(0.6em);
transform: translateY(0.6em);
}
#cp_toggle03:checked+.cp_mobilebar .cp_menuicon {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
#cp_toggle03:checked+.cp_mobilebar span:before,
#cp_toggle03:checked+.cp_mobilebar span:after {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
#cp_toggle03:checked~.cp_offcm03 {
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
#cp_toggle03:checked~.cp_container {
-webkit-transform: translateX(250px);
transform: translateX(250px);
}
input:checked~#h-menu_black {
display: block;
opacity: .6;
}
#h-menu_black {
display: none;
position: fixed;
z-index: 999;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: black;
opacity: 0;
transition: .7s ease-in-out;
}
/* content */
.cp_container {
top: 60px;
height: 92vh;
text-align: center;
}
.noscroll {
overflow: hidden;
position: fixed;
}
}
<div class="cp_cont">
<input id="cp_toggle03" type="checkbox">
<div class="cp_mobilebar">
<label for="cp_toggle03" class="cp_menuicon">
<span></span>
</label>
</div>
<label id="h-menu_black" class="cp_toggle03" for="cp_menuicon"></label>
<div id="body" class="noscroll"></div>
<header class="cp_offcm03">
<nav>
<ul style="text-align: center; margin-left: 210px; overflow: hidden;">
<li style="border-bottom: 1px solid lightgray;">Home</li>
<li style="border-bottom: 1px solid lightgray;">Blog</li>
<li style="border-bottom: 1px solid lightgray;">About This Website</li>
<li style="border-bottom: 1px solid lightgray;">Bibliography</li>

css transition between background gradient when checkbox is triggered

I've been trying to make a toggleable button through css, and I've been wondering if there's a way to transition between these two states smoothly when the checkbox is clicked, I've managed to do it without animations but it'd be neat if it was possible to anime the transition
toggle-button {
position: relative;
display: inline-block;
width: 120px;
height: 40px;
margin-left: 100px;
}
.toggle-button input{
opacity: 0;
height: 0;
width: 0;
}
.options-wrapper {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to right, white 50%, gray 50%);
border-radius:3px;
}
.button-options {
display: grid;
grid-template-columns: 1fr 1fr;
justify-items: center;
align-items: center;
height: 100%;
width: 100%;
background: linear-gradient(to right, black 50%, white 50%);
-webkit-background-clip: text;
-webkit-transition: .4s;
transition: .4s;
cursor: pointer;
}
.toggle-button input:checked + .options-wrapper {
background: linear-gradient(to right, gray 50%, white 50%);
}
.toggle-button input:checked + .options-wrapper > .button-options {
background: linear-gradient(to right, white 50%, black 50%);
-webkit-background-clip: text;
}
#keyframes shiftOpacity {
from { opacity: 0; }
to { opacity: 1; }
}
.button-options > p {
color: transparent
}
<label class="toggle-button">
<input type="checkbox">
<div class="options-wrapper">
<div class="button-options">
<p>Daily</p>
<p>Hourly</p>
</div>
</div>
</label>
This seems to work, i created a background div that goes back and forth when the input is checked, i also changed how the text change colors.
toggle-button {
position: relative;
display: inline-block;
width: 120px;
height: 40px;
margin-left: 100px;
}
.toggle-button input{
opacity: 0;
height: 0;
width: 0;
}
.options-wrapper {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius:3px;
}
.button-options {
display: grid;
grid-template-columns: 1fr 1fr;
justify-items: center;
align-items: center;
height: 100%;
width: 100%;
color: gray;
cursor: pointer;
position: relative;
}
.button-options .bg {
position: absolute;
height: 100%;
width: 50%;
left: 0;
background: gray;
transition: .5s ease-in-out;
}
.toggle-button input:checked + .options-wrapper .bg {
left: 50%;
}
.toggle-button input + .options-wrapper p:first-of-type {
color: white;
}
.toggle-button input:checked + .options-wrapper p:first-of-type {
color: gray;
}
.toggle-button input:checked + .options-wrapper p:last-of-type {
color: white;
}
.button-options p {
position: relative;
transition: .5s ease-in-out;
}
<label class="toggle-button">
<input type="checkbox">
<div class="options-wrapper">
<div class="button-options bg-left">
<div class="bg"></div>
<p>Daily</p>
<p>Hourly</p>
</div>
</div>
</label>

CSS transition not smooth for one element on hover, but is smooth when mouse moved away

I've got the following CSS and HTML. The problem is, that when the mouse is moved over the button, the red rectangle flashes to the center instead of smoothly moving to the center. It is strange because when the mouse is moved away from the button, it moves back slowly. How can I make the red rectangle move to the center smooth?
.btn {
position: relative;
display: inline-block;
padding: 30px 45px;
margin: 80px;
cursor: pointer;
}
.btn .rect {
transition: all 0.5s linear;
height: 100%;
width: 100%;
opacity: 0.3;
position: absolute;
}
.btn .top-left {
top: -10px;
left: -10px;
}
.btn .bottom-right {
bottom: -10px;
right: -10px;
}
.red-translucent {
background-color: red;
}
.blue-translucent {
background-color: blue;
}
.btn-text {
z-index: 99999;
position: relative;
font-family: Arial;
}
.btn:hover .rect {
top: 0;
bottom: 0;
left: 0;
right: 0;
}
<div class='btn'>
<span class='btn-text'>button</span>
<div class='rect top-left blue-translucent'></div>
<div class='rect bottom-right red-translucent'></div>
</div>
For some reason, it didn't work with bottom: -10px and right: -10px. I'm not sure if this has to do with my code or if this is a browser problem, but the easy fix is to use the top and left properties instead:
.btn {
position: relative;
display: inline-block;
padding: 30px 45px;
margin: 80px;
cursor: pointer;
}
.btn .rect {
transition: all 0.5s linear;
height: 100%;
width: 100%;
opacity: 0.3;
position: absolute;
}
.btn .top-left {
top: -10px;
left: -10px;
}
.btn .bottom-right {
top: 10px;
left: 10px;
}
.red-translucent {
background-color: red;
}
.blue-translucent {
background-color: blue;
}
.btn-text {
z-index: 99999;
position: relative;
font-family: Arial;
}
.btn:hover .rect {
top: 0;
bottom: 0;
left: 0;
right: 0;
}
<div class='btn'>
<span class='btn-text'>button</span>
<div class='rect top-left blue-translucent'></div>
<div class='rect bottom-right red-translucent'></div>
</div>
.red-translucent {
background-color: red;
top: 10px;
left: 10px;
}
Use transform instead of top, left, bottom, right like this:
.btn {
position: relative;
display: flex;
padding: 30px 45px;
margin: 80px;
cursor: pointer;
justify-content: center;
align-items: center;
width: 50px;
height: 50px;
}
.btn .rect {
transition: all 0.5s linear;
height: 100%;
width: 100%;
opacity: 0.3;
position: absolute;
}
.btn .top-left {
transform: translate(-10px, -10px);
}
.btn .bottom-right {
transform: translate(10px, 10px);
}
.red-translucent {
background-color: red;
}
.blue-translucent {
background-color: blue;
}
.btn-text {
z-index: 99999;
position: relative;
font-family: Arial;
}
.btn:hover .rect {
transform: translate(0px, 0px);
}
This will work smoothly on either the move-in or move-out of the pointer.

Align horizontally with % in CSS

I've made a sort of diagram with temperature values and a schedule for it. Now I want to align the time-tags perfectly with the middle of my gaps between the "blocks". The first one works with position:absolute and left:(%-px/2), but the second and third example are off. How does one align these boxes?
The Fiddle is HERE.
body {
background-color: #DDD;
}
a {
cursor: pointer;
}
.block {
display: block;
height: 100%;
color: #FFF;
font-size: .75em;
float: left;
position: relative;
opacity: 1;
transition: opacity, 0.4s ease; /* hover effect transition */
border-radius: 5px;
}
.block:nth-child(n+2) {
margin-left: 0.5%;
}
.block:hover {
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 3px 10px 0 rgba(0, 0, 0, 0.19);
}
.block.cool,
.legend li:nth-of-type(1):before {
background-color: #41A6F0;
}
.block.hot,
.legend li:nth-of-type(2):before {
background-color: #E27A3F;
}
.paused.cool {
background-color: #ccc;
}
.paused.hot {
background-color: #bbb;
}
.barchart {
display: grid;
margin: 0;
grid-template-columns:
[viewport-start] minmax(0.57em, 1fr) [container-start] minmax(20em, 35em) [container-end] minmax(0.75em, 1fr) [viewport-end];
grid-auto-rows: 30px;
}
row {
padding: 5px;
grid-column: container;
grid-row: span 4;
line-height: 120px;
text-align: center;
width: 0%;
animation: expand 1.2s ease forwards;
/* see animation "expand" below */
}
timerow {
grid-column: container;
grid-row: span 1;
line-height: 14px;
text-align: center;
visibility: hidden;
animation: 1.3s blendin; /* see animation "blendin" below */
animation-fill-mode: forwards;
margin-top: -15px;
position: relative;
}
timerow a {
position: absolute;
height: 25px;
width: 44px;
font-size: 0.8em;
color: #919191;
background: #fff;
}
/*
timerow a:last-child {
float: right;
margin-right: -12px;
}
timerow a:first-child {
margin-left: -17px;
}
*/
tag {
grid-column: container;
padding-top: 8px;
font-size: 0.8em;
color: #919191;
}
/* Big-Screen Design */
#media screen and (min-width: 768px) {
.barchart {
margin-left: -4.5em;
grid-template-columns:
[viewport-start] minmax(0.5em, 1fr) [axis-start] minmax(2em, 8em) [container-start] minmax(36em, 3fr) [container-end] minmax(0.5em, 1fr) [viewport-end];
}
tag {
grid-column: axis-start/container-start;
grid-row: span 4;
line-height: 120px;
padding: 0;
text-align: center;
}
}
/* intro animation */
#keyframes expand {
from {
width: 0%;
}
to {
width: calc(100% - 12px);
}
}
#keyframes blendin {
99% {
visibility: hidden;
}
100% {
visibility: visible;
}
}
#media screen and (min-width: 768px) {
#keyframes expand {
from {
width: 0%;
}
to {
width: calc(100% - 13px);
}
}
}
row:nth-child(4) {
animation-delay: .1s;
}
row:nth-child(6) {
animation-delay: .2s;
}
<div class="barchart">
<tag>Workday</tag>
<row>
<a style="width:28.9444444444%;" class="block cool">19deg</a>
<a style="width:63.805555555%;" class="block hot">21deg</a>
<a style="width:6.25%;" class="block hot">22deg</a>
</row>
<timerow>
<a style="left:calc(29.1944% - 22px);">07:30</a>
<a style="left:calc(93.5% - 22px);">22:30</a>
</timerow>
<tag>Weekend</tag>
<row>
<a style="width:44%;" class="block cool">16deg</a>
<a style="width:16%;" class="block paused hot">21deg</a>
<a style="width:38.5%;" class="block paused cool">18deg</a>
</row>
<timerow>
<a style="left:calc(44% - 22px);">00:00</a>
<a style="left:calc(60.75% - 22px);">00:00</a>
</timerow>
</div>
timerow a {
position: absolute;
height: 25px;
width: 44px;
font-size: 0.8em;
color: #919191;
background: #fff;
}
this one get's positioned too far right,
<a style="left:calc(93.5% - 22px);">22:30</a>
while this one works perfectly, where the ":" is centered in the gap:
<a style="left:calc(29.1944% - 22px);">07:30</a>
Even though I added the % numbers and factored in the 0.5% gap and subtracted the 22px for half the width of the box.
You also have the padding that you need to account for since position:absolute consider the padding-box to do the calculation. Add margin to timerow equal to the padding applied to row and you calculation will be correct.
You can also simplify the -22px with a translation. Also consider box-sizing:border-box; to your row element instead of decreasing the width in the animation.
body {
background-color: #DDD;
}
a {
cursor: pointer;
}
.block {
display: block;
height: 100%;
color: #FFF;
font-size: .75em;
float: left;
position: relative;
opacity: 1;
transition: opacity, 0.4s ease; /* hover effect transition */
border-radius: 5px;
}
.block:nth-child(n+2) {
margin-left: 0.5%;
}
.block:hover {
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 3px 10px 0 rgba(0, 0, 0, 0.19);
}
.block.cool,
.legend li:nth-of-type(1):before {
background-color: #41A6F0;
}
.block.hot,
.legend li:nth-of-type(2):before {
background-color: #E27A3F;
}
.paused.cool {
background-color: #ccc;
}
.paused.hot {
background-color: #bbb;
}
.barchart {
display: grid;
margin: 0;
grid-template-columns:
[viewport-start] minmax(0.57em, 1fr) [container-start] minmax(20em, 35em) [container-end] minmax(0.75em, 1fr) [viewport-end];
grid-auto-rows: 30px;
}
row {
padding: 5px;
box-sizing:border-box;
grid-column: container;
grid-row: span 4;
line-height: 120px;
text-align: center;
width: 0%;
animation: expand 1.2s ease forwards;
/* see animation "expand" below */
}
timerow {
grid-column: container;
grid-row: span 1;
line-height: 14px;
margin:0 5px;
text-align: center;
visibility: hidden;
animation: 1.3s blendin; /* see animation "blendin" below */
animation-fill-mode: forwards;
margin-top: -15px;
position: relative;
}
timerow a {
position: absolute;
height: 25px;
width: 44px;
font-size: 0.8em;
color: #919191;
background: #fff;
transform:translateX(-50%);
}
tag {
grid-column: container;
padding-top: 8px;
font-size: 0.8em;
color: #919191;
}
/* Big-Screen Design */
#media screen and (min-width: 768px) {
.barchart {
margin-left: -4.5em;
grid-template-columns:
[viewport-start] minmax(0.5em, 1fr) [axis-start] minmax(2em, 8em) [container-start] minmax(36em, 3fr) [container-end] minmax(0.5em, 1fr) [viewport-end];
}
tag {
grid-column: axis-start/container-start;
grid-row: span 4;
line-height: 120px;
padding: 0;
text-align: center;
}
}
/* intro animation */
#keyframes expand {
from {
width: 0%;
}
to {
width: 100%;
}
}
#keyframes blendin {
99% {
visibility: hidden;
}
100% {
visibility: visible;
}
}
row:nth-child(4) {
animation-delay: .1s;
}
row:nth-child(6) {
animation-delay: .2s;
}
<div class="barchart">
<tag>Workday</tag>
<row>
<a style="width:28.9444444444%;" class="block cool">19deg</a>
<a style="width:63.805555555%;" class="block hot">21deg</a>
<a style="width:6.25%;" class="block hot">22deg</a>
</row>
<timerow>
<a style="left:calc((28.9444444444 + 0.5/2)*1%);">07:30</a>
<a style="left:calc((28.9444444444 + 63.805555555 + 0.5 + 0.5/2)*1%);">22:30</a>
</timerow>
<tag>Weekend</tag>
<row>
<a style="width:44%;" class="block cool">16deg</a>
<a style="width:16%;" class="block paused hot">21deg</a>
<a style="width:38.5%;" class="block paused cool">18deg</a>
</row>
<timerow>
<a style="left:calc(44% + 0.5%/2);">00:00</a>
<a style="left:calc(44% + 16% + 0.5% + 0.5%/2);">00:00</a>
</timerow>
</div>

Resources