I've been asked to take a pure CSS3 loading spinner and make it dynamically resizable by pixels to use in different places in a program.
My current code is: (Which apparently doesn't run well in SO's snippets)
.loader {
animation:spin 1s infinite linear;
border:solid 2vmin transparent;
border-radius:50%;
border-right-color:#71c491;
border-top-color:#f7941d;
box-sizing:border-box;
height:20vmin;
left:calc(50% - 10vmin);
position:fixed;
top:calc(50% - 10vmin);
width:20vmin;
z-index:1;
&:before {
animation:spin 2s infinite linear;
border:solid 2vmin transparent;
border-radius:50%;
border-right-color:#21409a;
border-top-color:#92278f;
box-sizing:border-box;
content:"";
height:16vmin;
left:0;
position:absolute;
top:0;
width:16vmin;
}
&:after {
animation:spin 3s infinite linear;
border:solid 2vmin transparent;
border-radius:50%;
border-right-color:#13b0e6;
border-top-color:#18244c;
box-sizing:border-box;
content:"";
height:12vmin;
left:2vmin;
position:absolute;
top:2vmin;
width:12vmin;
}
}
#keyframes spin {
100% {
transform:rotate(360deg);
}
}
<div class="loader"></div>
I googled and tried transform:scale() but as far as I can tell that only takes specific input and increases/decreases the size by percentage. (2 = 200% size)
I'm thinking I need some sort of wrapper, but I'm not too familiar with advanced CSS to get the effect. When I tried to create my own, only the top border of the spinner would be resized into a weird shape and not the inner borders. I'm just stumped. If you could point me in the right direction, I'd be appreciative. Thank you.
You could try a mix of CSS var() / calc() / clamp() / grid ... and relative/absolute positionning to lay the loader over the parent where you need it , if that inspire you :
demo with a few loader within a div sized and the possibility to set an average size to start from, % size based on the width of the parent.
value to reset in the demo is --size ; you may also tune the other --MyVarCss values to your needs.
* {
box-sizing: border-box;
}
:root { /* init for the var() values */
--size: 20;/* value used to set the loader's width and adjust border's width */
--width: calc(var(--size) * 1%);
--widthBorder: calc( clamp(20px, 6vw, 80px) * var(--size) * 0.005);
}
.a,/* for the demo , just a bunch of containers */
.b,
.c,
.d,
.d,
.e {
position: relative;
/* what the parent loader needs to be (absolute/fixed/sticky works too, static not) */
float: left;
border: solid;
margin: 1em;
}
div.a {
--size: 50; /* reset the value used to set the loader's width */
width: 50%;
padding-top: 50%;
}
.b {
--size: 10;/* reset the value used to set the loader's width */
width: 600px;
height: 200px;
}
.c {
--size: 15;/* reset the value used to set the loader's width */
width: 25%;
padding-top: 20%;
}
.d {
--size: 30;/* reset the value used to set the loader's width */
width: 800px;
height: 400px;
}
.e {
--size: 14;/* reset the value used to set the loader's width */
width: 90%;
min-height: 20vh;
}
div {
width: 20%;
padding-top: 20%;
}
/* loader styles */
.loader {
position: absolute;
top: 0;
left: 0;
display: flex;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.loader b {
display: grid;
animation: rotate 3s -1s infinite linear;
border: solid var(--widthBorder) transparent;
padding: calc(var(--widthBorder) / 2);
border-radius: 50%;
border-right-color: #71c491;
border-top-color: #f7941d;
grid-row: 1;
grid-column: 1;
margin: 0;
}
.loader>b {
margin: auto;
width: var(--width);
}
.loader>b:before {
content: "";
padding-top: 100%;
grid-row: 1;
grid-column: 1;
}
.loader b b {
border-right-color: #21409a;
border-top-color: #92278f;
}
.loader b b b {
border-right-color: #13b0e6;
border-top-color: #18244c;
padding: 0;
}
#keyframes rotate {
100% {
transform: rotate(360deg);
}
}
<div class=a>
<div class="loader"><b><b><b></b></b>
</b>
</div>
</div>
<div class=b>
<div class="loader"><b><b><b></b></b>
</b>
</div>
</div>
<div class=c>
<div class="loader"><b><b><b></b></b>
</b>
</div>
</div>
<div class=d>
<div class="loader"><b><b><b></b></b>
</b>
</div>
</div>
<div class=e>
<div class="loader"><b><b><b></b></b>
</b>
</div>
</div>
I've got a simple display that flips over on click. I want to add a little bounce to the movement by rotating a few degrees in the opposite direction before rotating the full 180 degrees to reveal the opposite side.
RotateX() will accept more than one instance inline, but it calculates the end result and does not show both directions. ie:
transform: rotateX(-10deg) rotateX(190deg)
this results in the object rotating 180deg.
I've tried comma separating them, as well as just putting two sets of degress in the parens, with similar results.
I've tried putting both steps into #keyframes, but animation doesn't seem to work with my on-click event in javascript.
I've also tried having each direction of rotation in a separate class that are both activated via classlist.toggle, but still do not see both directions of rotation.
here's a codepen with the above mocked up:
https://codepen.io/Boreetos22/pen/WNrJEvR
I'd appreciate any insight. Thanks!
Transitions probably won't get what you want since you can't fake the bounce with multiple steps. #keyframes will work but you can't simply toggle the class. You need to add one and then add another to reset it.
Also, you'll need multiple animations (forward and back) that you change on over/out and click.
let sides = document.querySelector('.sides');
sides.addEventListener( 'click', function(e) {
if(sides.classList.contains('flip-forward')){
sides.classList.remove('flip-forward');
sides.classList.add('flip-backward');
}else{
sides.classList.add('flip-forward');
sides.classList.remove('flip-backward');
}
});
* {
padding: 0;
margin: 0;
}
h2 {
margin-top: 12px;
font-size: 30px;
}
body {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.container {
display: flex;
justify-content: center;
height: 60px;
width: 400px;
perspective: 1000px;
}
#keyframes myAnimationFwrd {
/* has bounce */
24% {
transform: rotateX( -40deg)
}
36% {
transform: rotateX( 0)
}
100% {
transform: rotateX( 190deg)
}
}
#keyframes myAnimationBkwrd {
/* no bounce add more steps to enable */
0% {
transform: rotateX( 190deg)
}
100% {
transform: rotateX( 0deg)
}
}
.flip-forward {
animation: myAnimationFwrd 1s forwards;
}
.flip-backward {
animation: myAnimationBkwrd 1s forwards;
}
.sides {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
position: relative;
transform-style: preserve-3d;
cursor: pointer;
}
.red, .black {
text-align: center;
color: white;
height: 100%;
width: 100%;
border-radius: 30px;
box-shadow: 2px 2px 4px black;
position: absolute;
backface-visibility: hidden;
}
.red {
background-color: darkred;
z-index: 2;
}
.black {
background-color: black;
z-index: 1;
transform: rotateX(180deg);
}
<div class="container">
<div class="sides">
<div class="red">
<h2>PLAYER ONE'S TURN</h2>
</div>
<div class="black">
<h2>PLAYER TWO'S TURN</h2>
</div>
</div>
</div>
I have 2 divs 50% width each. There is a huge header h1 which should have the color of these two divs. I have tried mix-blend-mode but it gives me some random colors when set to difference. My goal is to invert the colors but to keep the colors of the divs. This is a codepen file, I have tried to keep it as simple as possible: https://codepen.io/lukagurovic/pen/MLoZmj
The final effect is supposed to look like on in this example:
https://jsfiddle.net/1uubdtz6/
but I am not sure why doesn't it work with these colors.
Also, these divs are interactive so the color has to change dynamicly as divs are increasing in width when hovered, and there should be only stroke of text without any fill
body {
height: 100vh;
width: 100%;
position: relative;
background-color: #510035;
margin: 0 auto;
}
h1 {
font-size: 4.7em;
text-transform: uppercase;
}
.half-pager {
width: 50%;
height: 100%;
position: absolute;
display: inline-block;
overflow: hidden;
text-align: center;
}
.half-pager-dark {
background-color: #510035;
}
.half-pager-light {
right: 0;
background-color: #E8E8E8;
float: right;
}
.lp-header {
position: absolute;
}
.lp-header {
color:transparent;
mix-blend-mode: difference;
-webkit-text-stroke: 3px rgb(126, 124, 133);
z-index: 1;
}
.lp-header {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
<div id="box" class="half-pager half-pager-dark"></div>
<div id="box1" class="half-pager half-pager-light"></div>
<h1 class="lp-header">left or right</h1>
One idea is to duplicate the text and use CSS variable to define the color so you can easily change them in one place. I used clip-path to hide half of one text and show the other half:
body {
margin: 0;
--c1:#510035;
--c2:#E8E8E8;
}
body:hover {
--c1:red;
--c2:blue;
}
h1 {
font-size: 4.7em;
text-transform: uppercase;
margin: 0;
}
.first {
background:var(--c1);
-webkit-text-stroke: 3px var(--c2);
}
.second {
background:var(--c2);
-webkit-text-stroke: 3px var(--c1);
clip-path:polygon(0% 0%, 50% 0%, 50% 100%,0% 100%);
}
.lp-header {
position:absolute;
top:0;
left:0;
right:0;
min-height:100vh;
box-sizing:border-box;
color: transparent;
z-index: 1;
padding: 50px;
text-align: center;
transition:0.5s;
}
<h1 class="lp-header first">left or right</h1>
<h1 class="lp-header second">left or right</h1>
When we use CSS3 transform: operation1(...) operation2(...), which one is done first?
The first operation done seems to be the one the most on the right., i.e. here operation2 is done before operation1. Just to be sure, is it true?
Note: I have read one thing and its contrary in some places (answers, articles on the internet), thus the question here.
Yes, the first operation done is the one the most on the right., i.e. here operation2 is done before operation1.
This MDN article states indeed:
The transform functions are multiplied in order from left to right, meaning that composite transforms are effectively applied in order from right to left.
Here is the documentation : http://www.w3.org/TR/css-transforms-1/.
Example 1
Here the scaling is done first, and then the translation of 100px vertically (if translation was done first, the scaling would make the translation of 500px!)
#container {
position: absolute;
transform: translate(0,100px) scale(5);
transform-origin: 0 0; }
<div id="container"><img src="https://i.stack.imgur.com/xb47Y.jpg"></img></div>
Example 2
Here the translation is done first, and then the scaling (the scaling done after makes that the translation looks like a 500px-translation!)
#container {
position: absolute;
transform: scale(5) translate(0,100px);
transform-origin: 0 0; }
<div id="container"><img src="https://i.stack.imgur.com/xb47Y.jpg"></img></div>
This has been mentioned in other answers and comments, but not with enough emphasis in my opinion: the short answer is both ways are valid.
It all depends whether you consider your coordinates attached to your element (left to right) or fixed to the page based on the initial element position (right to left).
Here is an article showing the difference with animations (which makes it easier to understand): Chaining transforms.
Here is a snippet showing the animations from the article:
html, body { height: 100%; }
body {
background: #aaa;
color: #000;
font-family: Calibri,Candara,Segoe,"Segoe UI",Optima,Arial,sans-serif;
overflow: hidden;
margin: 0;
}
.info {
text-align: center;
font-family: Consolas,monaco,monospace;
font-size: 20px;
font-weight: bold;
margin-bottom: 4px;
color: #fff;
}
.split { white-space: nowrap; }
.side {
display: inline-block;
width: 50%;
}
.label {
text-align: center;
font-size: 20px;
}
.container {
position: relative;
font-size: 50px;
margin: .6em auto 0;
width: 0; height: 0;
transform: translateX(-1em);
}
.ltr .object {
position: absolute;
left: 0; top: 0;
width: 1em; height: 1em;
margin: -.5em 0 0 -.5em;
background: rgb(114,34,34);
animation: ltrObj 5s infinite;
}
#keyframes ltrObj {
from, 10% { transform: rotate( 0deg) translateX(0em); }
40% { transform: rotate(45deg) translateX(0em); }
70%, to { transform: rotate(45deg) translateX(2em); }
}
.object.shadow {
animation: none;
opacity: .2;
}
.ltr .axes {
position: absolute;
left: .5em; top: .5em;
width: 1em; height: 1em;
color: #111;
box-sizing: border-box;
border-left: 2px solid;
border-top: 2px solid;
}
.ltr .axes::before, .ltr .axes::after {
content: '';
position: absolute;
width: .2em; height: .2em;
box-sizing: border-box;
border-left: 2px solid;
border-top: 2px solid;
transform-origin: top left;
}
.ltr .axes::before { top: 100%; left: 0; margin-left: -1px; margin-top: 1px; transform: rotate(225deg); }
.ltr .axes::after { top: 0; left: 100%; margin-top: -1px; margin-left: 1px; transform: rotate(135deg); }
.rtl .axes {
position: absolute;
left: 0; top: 0;
width: 2.5em; height: 2.3em;
color: #111;
box-sizing: border-box;
border-left: 2px solid;
border-top: 2px solid;
}
.rtl .axes::before, .rtl .axes::after {
content: '';
position: absolute;
width: .2em; height: .2em;
box-sizing: border-box;
border-left: 2px solid;
border-top: 2px solid;
transform-origin: top left;
}
.rtl .axes::before { top: 100%; left: 0; margin-left: -1px; margin-top: 1px; transform: rotate(225deg); }
.rtl .axes::after { top: 0; left: 100%; margin-top: -1px; margin-left: 1px; transform: rotate(135deg); }
.rtl .object {
position: absolute;
left: 0; top: 0;
width: 1em; height: 1em;
margin: -.5em 0 0 -.5em;
background: rgba(100,0,0,0.8);
animation: rtlObj 5s infinite;
}
#keyframes rtlObj {
from, 10% { transform: rotate( 0deg) translateX(0em); }
40% { transform: rotate( 0deg) translateX(2em); }
70%, to { transform: rotate(45deg) translateX(2em); }
}
.helper-mask {
position: absolute;
left: 0; top: 0;
width: 3em; height: 3em;
overflow: hidden;
}
.helper {
position: absolute;
left: 0; top: -2em;
width: 0; height: 2em;
margin-top: 2px;
box-sizing: border-box;
border: 2px solid #00c;
border-left: none;
border-radius: 0 100% 0 0;
transform-origin: bottom left;
animation: helper 5s infinite;
}
#keyframes helper {
from, 10% { width: 0em; transform: rotate( 0deg); }
40% { width: 2em; transform: rotate( 0deg);}
70%, to { width: 2em; transform: rotate(45deg);}
}
<div class="info">rotate(45deg) translateX(2em)</div>
<div class="split">
<div class="side ltr">
<div class="label">Left to Right</div>
<div class="container">
<div class="object shadow"></div>
<div class="object">
<div class="axes"></div>
</div>
</div>
</div>
<div class="side rtl">
<div class="label">Right to Left</div>
<div class="container">
<div class="axes"></div>
<div class="object"></div>
<div class="helper-mask">
<div class="helper"></div>
</div>
</div>
</div>
</div>
Whether the actual implementation uses left to right or right to left is irrelevant, both are equally valid when creating an animation, as long as you keep the difference in mind.
Transforms are performed left to right. Transforms correspond to matrix operations, and these are performed left to right.
There is intuition behind it, it's not just that this is literally in the spec as a normative rule (point 3 here: https://drafts.csswg.org/css-transforms-1/#transform-rendering)
Here's a pen to try: https://codepen.io/monfera/pen/YLWGrM
Explanation:
Each transform step establishes its own coordinate system. So
transform: translateX(500px);
establishes a new coordinate system 500px along the X axis of its parent, and the element will be rendered there.
Similarly,
background-color: blue;
transform: translateX(500px) rotate(60deg);
first establishes a new coordinate system 500px along the X axis (to the right) of its parent, and only then, within that (translated, but it's now irrelevant) coordinate system does it perform the rotation. So it'll be a shape that's 500px to the right, and rotated in place (around the so-called transform-origin which is interpreted in the local coordinate system, and the default 50% 50% for rotation means, rotation around the center of the rectangle, but it's an aside).
The reverse order
background-color: orange;
transform: rotate(60deg) translateX(500px);
first establishes a new coordinate system that's rotated 60 degrees relative to the parent, and then translates 100px along the X axis of the now rotated coordinate system, in a direction that is not actually to the right from the global viewpoint of the document (or user). So, in this case, it's as if you first rotated the paper, and then slid the shape 500 units along the side of the paper (from the origin, which is in this case the top left corner).
For a more advanced discussion, and understanding of how it's possible to intuitively understand it for both directions, check out Composing Transformations - CSS transforms follow the post-multiplication model, so look for the page with the heading "Think of transformations as transforming the local coordinate frame" (illustrations seem to be a little off though)
It applies the leftmost transformation first.
As you can see in the image above, the first transformation takes a longer distance as compared to the second. The reason is the first example undergoes scale first and then it takes the distance specified by translate based on its new width on the x-axis. Because it is wider now, 50% will cause it to take a longer distance. The measure specified by 50% is calculated by taking half of the width of itself.
the site I cited from
I just created a demo of a 3d room in HTML using CSS transforms. I made a 200x200 DIV for a back wall, leaving it in that position. Then I made a left wall starting in the same size and position, then added
transform: translate3d(-100px,0px,100px) rotateY(90deg).
Then I made a right wall and added
transform: translate3d( 100px,0px,100px) rotateY(90deg).
This created the room correctly. But this is with version 13 of Safari. Originally I tried to list the rotation step first, but the wall was in an odd position. So I'm seeing a right-to-left behavior.
I found a great stackoverflow answer on how to create a hexagonal patten using CSS.
Generate repeating hexagonal pattern with CSS3
It's almost perfect, except i'd like to flip the hexagons the other way (ie. so the point is at the top). I've managed to do this fairly easily by swapping the main hex div width/height: (hexrow > div)... however i'm really struggling to re-align the background image on the other supporting divs. I've been trying to figure it out for a while now without much success.
Could anyone possibly post a jsFiddle that shows how it's done?
This is where i'm at currently: What i've tried
..and i believe this is what i need to amend:
.hexrow > div > div:first-of-type:before {
content: '';
position: absolute;
width: 200px; /* width of main + margin sizing */
height: 100%;
background-image: inherit;
background-position: 0 0;
background-repeat: no-repeat;
background-size: 120% auto;
bottom: 0;
left: 0;
z-index: 1;
-ms-transform:rotate(-60deg) translate(-150px, 0); /* IE 9 */
-moz-transform:rotate(-60deg) translate(-150px, 0); /* Firefox */
-webkit-transform:rotate(-60deg) translate(-150px, 0); /* Safari and Chrome */
-o-transform:rotate(-60deg) translate(-150px, 0); /* Opera */
transform:rotate(-60deg) translate(-150px, 0);
-ms-transform-origin: 0 0; /* IE 9 */
-webkit-transform-origin: 0 0; /* Safari and Chrome */
-moz-transform-origin: 0 0; /* Firefox */
-o-transform-origin: 0 0; /* Opera */
transform-origin: 0 0;
}
Any help much appreciated.
Use :nth-of-type(odd) and :nth-of-type(even) and set different margins for odd/ even hexagons on the same row.
Or you could do it in a much simpler manner, with less markup - check my answer at that question and this demo I just did. The idea is that you apply a series of transforms on the element (which has overflow: hidden) in order to get a rhombus with an acute angle of 60 degrees and then you undo all those transforms in reverse order for a pseudo-element or a child element if you wish (having the same height as the element itself, but only .866 of its width, because .866 is the ratio of the distance between two parallel sides of a hexagon and its big diagonal) on which you actually apply the background-image. So there's no chance of misalignment, because the background image is only applied on one element.
Basic HTML structure:
<div class='row'>
<div class='hexagon'></div>
</div>
<div class='row'>
<div class='hexagon content ribbon' data-content='This is a test!!!
9/10'></div><!--
--><div class='hexagon content longtext' data-content='Some longer text here.
Bla bla bla bla bla bla bla bla bla bla blaaaah...'></div>
</div>
Relevant CSS:
.row { margin: -8% 0%; text-align: center; }
.row:first-child { margin-top: 2.25%; }
.hexagon {
position: relative;
display: inline-block;
overflow: hidden;
margin: 0 -1.5%;
padding: 16%;
transform: rotate(-30deg) skewX(30deg) scaleY(.866); /* .866 = sqrt(3)/2 */
}
.hexagon:before {
display: block;
position: absolute; /* 86.6% = (sqrt(3)/2)*100% = .866*100% */
right: 6.7%; bottom: 0; left: 6.7%; top: 0; /* 6.7% = (100% -86.6%)/2 */
transform: scaleY(1.155) skewX(-30deg) rotate(30deg); /* 1.155 = 2/sqrt(3) */
background-color: rgba(30,144,255,.56);
background-size: cover;
content: '';
}
.row:first-child .hexagon:first-child:before {
background-image: url(img.jpg);
}
/* and so on, add background images for all hexagons */
I used borders.
Codepen.io
<div id="hex"></div>
And
#hex {
display: inline-block;
position: relative;
width: 190px;
height: 220px;
background: no-repeat url("http://placekitten.com/200/300") 50% 50%;
}
div:before {
content: " ";
display: block;
border-top: 0px solid transparent;
border-bottom: 55px solid transparent;
order-left: 95px solid white;
border-right: 95px solid white;
}
div:after {
content: " ";
display: block;
border-left: 95px solid white;
border-top: 55px solid transparent;
border-right: 95px solid white;
margin-top:110px
}