Basically I want a child element to use it's parent dimensions to become a square, but it can't overflow so it needs to use the lowest value between height/width.
I know in practice there's no math.min in css, but maybe this can be achieve using a combination of flexbox or some other displays?
In the end what I'm trying to achieve is a responsive "loading spinner" class that works on any element only using css and without needing to add anything but a class.
This fiddle exemplifies my issues : http://jsfiddle.net/ppgab/adfnc5tk/40/
/*Spinner with overlay and no mouse events*/
#keyframes spinner {
to {transform: rotate(360deg);}
}
.loading::before {
position:absolute;
content : '';
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: gray;
z-index: 2;
opacity: 0.2;
}
.loading::after {
content: '';
box-sizing: border-box;
position: absolute;
top: 50%;
left: 50%;
width: 25%;
margin-top: -12.5%;
margin-left: -12.5%;
border-radius: 50%;
border: solid transparent;
border-top-color: #07d;
border-bottom-color: #07d;
animation: spinner 1s ease infinite;
z-index: 3;
padding-top: calc(12.5% - .5em);
border-width: .5em;
padding-bottom: calc(12.5% - .5em);
}
.loading.loading-sm::after {
content: '';
box-sizing: border-box;
position: absolute;
top: 50%;
left: 50%;
width: 25%;
margin-top: -12.5%;
margin-left: -12.5%;
border-radius: 50%;
border: solid transparent;
border-top-color: #07d;
border-bottom-color: #07d;
animation: spinner 1s ease infinite;
z-index: 3;
padding-top: calc(12.5% - .1em);
border-width: .1em;
padding-bottom: calc(12.5% - .1em);
}
.loading {
position: relative;
pointer-events: none;
cursor: wait;
}
.body {
text-align:center;
height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
padding : 1rem;
align-items: center;
}
.inner-div {
background-color: red;
width: 500px;
height: 100px;
}
<body class="body">
<h1 class="loading">
If you increase this width too much it overflows, since the sizing is based on width
</h1>
<h3>
But if you reduce the width too much it gets ugly :(
</h3>
<button style="font-size:2rem;width:200px;margin:1rem" class="loading loading-sm">
Button
</button>
<div class="inner-div loading">
This fixed element doesn't work either
</div>
</body>
I'm quite a beginner in css, the above code is mix of several online examples so I don't really know what I'm doing.
Related
I'm trying to replicate a graphical design using css, but I have failed for responsive, I can achieve an static form but with tiny defects (due to putting together two elements).
This is the graphical design:
I prefer it a bit more tilted, like: skew(-40deg). But the idea is to have an inner rounded border that wraps that key-button just like in the image.
The html is simple:
<header>
<nav></nav>
</header>
The css:
body > header > nav {
display: flex;
align-items: flex-end;
justify-content: center;
width: 100vw;
height: 90px;
padding: 10px 0;
text-align: center;
z-index: 1
}
body > header > nav::before {
content: '';
position: absolute;
top: 0; left: 0;
width: 80vw; height: 100%;
background-color: rgb(147, 147, 147);
border-bottom-right-radius: 15px;
transform: skew(-40deg);
transform-origin: 100% 0%;
}
body > header > nav::after {
content: '';
position: absolute;
top: 0; right: 0;
width: 28.7%;
border-top: 7px solid rgb(147, 147, 147);
border-left: 50px solid rgb(147, 147, 147);
height: 75px;
border-top-left-radius: 75px;
transform: skew(-33deg);
}
I've prepared a https://jsfiddle.net/uj4qsf37/
Is there a cleaner way to do this? Like not having to use two elements? With one element it would be easy to make it responsive.
I would do it like this:
.header {
border-top: 20px solid blue;
height:100px;
position: relative;
overflow: hidden;
}
.header:before,
.header:after {
content: "";
vertical-align:top;
display: inline-block;
transform-origin: top right;
transform: skew(-40deg);
}
.header:before {
height: 100%;
width: 50%;
border-radius: 0 0 20px 0;
background: blue;
}
.header:after {
height: 20px;
width: 20px;
margin-left:-1px;
background: radial-gradient(circle at bottom right, transparent 68%, blue 73%);
}
/*to illustrate different values of skew*/
.header:before,
.header:after {
animation:change 2s linear infinite alternate;
}
#keyframes change{
from{transform: skew(0deg);}
top{transform: skew(-40deg);}
}
<div class="header"></div>
I'm trying to replicate the styling of this animation but I don't know how to "fill in" the background color of the intersection of these two shapes. In the animation, the intersection is conveniently stepwise and stops where the edge of the square intersections with the origin of the circle; I can imagine using a clipping-mask to fill in that quadrant of the circle. However, is it possible to do the same more dynamically? Can you fill in the background of two intersecting shapes (while still having a transparent background otherwhere)?
.shape-interconnected {
width: 400px;
height: 300px;
position: relative;
background-color: black;
color: white;
margin: 1rem;
border-radius: 4px;
}
.shape-interconnected > .square, .shape-interconnected > .circle {
width: 50px;
height: 50px;
position: absolute;
border: 5px solid white;
transform: translate(-50%, -50%);
}
.shape-interconnected > .square {
border-radius: 4px;
top: 45%;
left: 55%;
}
.shape-interconnected > .circle {
border-radius: 50%;
top: 55%;
left: 45%;
}
<div class="shape-interconnected">
<div class="square"></div>
<div class="circle"></div>
</div>
You can recreate the dribble using html with a little css pseudo and animation magic.
This example below works at any set css variable set size border defined in the root css vars.
:root {
--size: 250px;
--border: 5px;
}
The trick in my example is by using positioning as percentages, meaning the parent .shape-interconnected controlled by the css var size, dictates all the child and child pseudo element position.
There is a lot of css to explain here, I've added comments in css, see if this inspires you to get you where you need to go...
Here is a fiddle... https://jsfiddle.net/joshmoto/378Lcgp0/
/* our root css vars */
:root {
--size: 250px;
--border: 5px;
}
BODY {
background: black;
min-height: 100%;
}
/* reset our box sizing on psuedo elems */
*, ::after, ::before {
box-sizing: border-box;
}
/* our shape intersect container positioned center of window */
/* this can be positioned where ever you want */
.shape-interconnected {
background: black;
width: var(--size);
height: var(--size);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
animation: shape-interconnected 2s infinite;
}
/* animate height and width equally */
#keyframes shape-interconnected {
0% {
width: var(--size);
height: var(--size);
}
50% {
width: calc(var(--size) * 0.6);
height: calc(var(--size) * 0.6);
}
100% {
width: var(--size);
height: var(--size);
}
}
/* our square calculated at 40% of parent */
/* position and overflow hidden are key, hiding pseudo child elems */
.shape-interconnected > .square {
width: calc(var(--size) * 0.4);
height: calc(var(--size) * 0.4);
background: transparent;
position: absolute;
overflow: hidden;
right: 0;
top: 0;
}
/* our square before pseudo elem emulating inner white filled circle */
/* position absolute with animation keyframes */
.shape-interconnected > .square::before {
content: "";
display: block;
width: 100%;
height: 100%;
background: #fff;
border-radius: 50%;
position: absolute;
animation: circle-interconnected 2s infinite;
}
/* start top/right 150% away, overflowing out of view */
/* 50% keyframe top/right 50% away, in view */
#keyframes circle-interconnected {
0% {
top: 150%;
right: 150%;
}
50% {
top: 50%;
right: 50%;
}
100% {
top: 150%;
right: 150%;
}
}
/* our square after pseudo elem emulating white border */
.shape-interconnected > .square::after {
content: "";
display: block;
width: 100%;
height: 100%;
background: transparent;
border: var(--border) solid white;
position: relative;
}
/* our circle calculated at 40% of parent */
.shape-interconnected > .circle {
width: calc(var(--size) * 0.4);
height: calc(var(--size) * 0.4);
position: absolute;
bottom: 0;
left: 0;
}
/* our circle after pseudo elem emulating white border */
.shape-interconnected > .circle::after {
content: "";
display: block;
width: 100%;
height: 100%;
background: transparent;
border: var(--border) solid white;
border-radius: 50%;
position: relative;
}
<div class="shape-interconnected">
<div class="square"></div>
<div class="circle"></div>
</div>
Here is another example using the same code above but with these css root var settings...
:root {
--size: 500px;
--border: 2px;
}
Live example below...
/* our root css vars */
:root {
--size: 500px;
--border: 2px;
}
BODY {
background: black;
min-height: 100%;
}
/* reset our box sizing on psuedo elems */
*, ::after, ::before {
box-sizing: border-box;
}
/* our shape intersect container positioned center of window */
/* this can be positioned where ever you want */
.shape-interconnected {
background: black;
width: var(--size);
height: var(--size);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
animation: shape-interconnected 2s infinite;
}
/* animate height and width equally */
#keyframes shape-interconnected {
0% {
width: var(--size);
height: var(--size);
}
50% {
width: calc(var(--size) * 0.6);
height: calc(var(--size) * 0.6);
}
100% {
width: var(--size);
height: var(--size);
}
}
/* our square calculated at 40% of parent */
/* position and overflow hidden are key, hiding pseudo child elems */
.shape-interconnected > .square {
width: calc(var(--size) * 0.4);
height: calc(var(--size) * 0.4);
background: transparent;
position: absolute;
overflow: hidden;
right: 0;
top: 0;
}
/* our square before pseudo elem emulating inner white filled circle */
/* position absolute with animation keyframes */
.shape-interconnected > .square::before {
content: "";
display: block;
width: 100%;
height: 100%;
background: #fff;
border-radius: 50%;
position: absolute;
animation: circle-interconnected 2s infinite;
}
/* start top/right 150% away, overflowing out of view */
/* 50% keyframe top/right 50% away, in view */
#keyframes circle-interconnected {
0% {
top: 150%;
right: 150%;
}
50% {
top: 50%;
right: 50%;
}
100% {
top: 150%;
right: 150%;
}
}
/* our square after pseudo elem emulating white border */
.shape-interconnected > .square::after {
content: "";
display: block;
width: 100%;
height: 100%;
background: transparent;
border: var(--border) solid white;
position: relative;
}
/* our circle calculated at 40% of parent */
.shape-interconnected > .circle {
width: calc(var(--size) * 0.4);
height: calc(var(--size) * 0.4);
position: absolute;
bottom: 0;
left: 0;
}
/* our circle after pseudo elem emulating white border */
.shape-interconnected > .circle::after {
content: "";
display: block;
width: 100%;
height: 100%;
background: transparent;
border: var(--border) solid white;
border-radius: 50%;
position: relative;
}
<div class="shape-interconnected">
<div class="square"></div>
<div class="circle"></div>
</div>
You might add a white circle inside the square and position it to the same coords the transparent one has.
Set overflow: hidden to the square to hide the outside part of the white circle:
.shape-interconnected {
width: 400px;
height: 300px;
position: relative;
background-color: black;
color: white;
margin: 1rem;
border-radius: 4px;
--animation-props: 1s alternate linear infinite;
}
.shape-interconnected>.square,
.shape-interconnected>.square:before,
.shape-interconnected>.circle {
width: 50px;
height: 50px;
position: absolute;
border: 5px solid white;
transform: translate(-50%, -50%)
}
.shape-interconnected>.square {
top: 35%;
left: 65%;
border-radius: 4px;
overflow: hidden;
animation: for_square var(--animation-props);
}
.shape-interconnected>.circle {
top: 65%;
left: 35%;
border-radius: 50%;
animation: for_transparent_circle var(--animation-props);
}
.shape-interconnected>.square:before {
content: '';
border-radius: 50%;
background: #fff;
top: 230%;
left: -190%;
animation: for_white_circle var(--animation-props);
}
#keyframes for_square {
to {
top: 50%;
left: 55%;
}
}
#keyframes for_transparent_circle {
to {
top: 55%;
left: 50%;
}
}
#keyframes for_white_circle {
to {
top: 80%;
left: 10%;
}
}
<div class="shape-interconnected">
<div class="square"></div>
<div class="circle"></div>
</div>
I'm trying to replicate a graphical design using css, but I have failed for responsive, I can achieve an static form but with tiny defects (due to putting together two elements).
This is the graphical design:
I prefer it a bit more tilted, like: skew(-40deg). But the idea is to have an inner rounded border that wraps that key-button just like in the image.
The html is simple:
<header>
<nav></nav>
</header>
The css:
body > header > nav {
display: flex;
align-items: flex-end;
justify-content: center;
width: 100vw;
height: 90px;
padding: 10px 0;
text-align: center;
z-index: 1
}
body > header > nav::before {
content: '';
position: absolute;
top: 0; left: 0;
width: 80vw; height: 100%;
background-color: rgb(147, 147, 147);
border-bottom-right-radius: 15px;
transform: skew(-40deg);
transform-origin: 100% 0%;
}
body > header > nav::after {
content: '';
position: absolute;
top: 0; right: 0;
width: 28.7%;
border-top: 7px solid rgb(147, 147, 147);
border-left: 50px solid rgb(147, 147, 147);
height: 75px;
border-top-left-radius: 75px;
transform: skew(-33deg);
}
I've prepared a https://jsfiddle.net/uj4qsf37/
Is there a cleaner way to do this? Like not having to use two elements? With one element it would be easy to make it responsive.
I would do it like this:
.header {
border-top: 20px solid blue;
height:100px;
position: relative;
overflow: hidden;
}
.header:before,
.header:after {
content: "";
vertical-align:top;
display: inline-block;
transform-origin: top right;
transform: skew(-40deg);
}
.header:before {
height: 100%;
width: 50%;
border-radius: 0 0 20px 0;
background: blue;
}
.header:after {
height: 20px;
width: 20px;
margin-left:-1px;
background: radial-gradient(circle at bottom right, transparent 68%, blue 73%);
}
/*to illustrate different values of skew*/
.header:before,
.header:after {
animation:change 2s linear infinite alternate;
}
#keyframes change{
from{transform: skew(0deg);}
top{transform: skew(-40deg);}
}
<div class="header"></div>
I am trying to make a sort of Venn-Diagram that is going to be used for navigation later.
I have three intersecting ellipsoids created with CSS shapes. Each ellipsoid, as well as their two intersections, will be distinct links later on. Also, when you hover over them they should pop out as per transform: scale(1.3).
My issue is that I'm using ellipsoids which are partially transparent with :after to create the intersections, which creates a problem when hovering over them because the :hover condition gets triggered when hovering anywhere on the partially transparent ellipsoid and not just the :after part. This means that the nonintersecting areas are not hoverable because they are obstructed by the other invisible ellipsoid.
I think the example will make this clearer.
Here is the code:
CSS:
.venn-container{position: relative; left: 0;}
.cat_one{
width: 400px;
height: 200px;
background: red;
border-radius: 200px / 100px;
position: absolute;
float: left;
opacity: 0.5;
}
.cat_two{
width: 400px;
height: 200px;
background: green;
border-radius: 200px / 100px;
position: absolute;
float: left;
left: 240px;
opacity: 0.5;
}
.cat_three{
width: 400px;
height: 200px;
background: blue;
border-radius: 200px / 100px;
position: absolute;
float: left;
left: 480px;
opacity: 0.5;
}
.int1{
background: transparent;
width: 400px;
height: 200px;
border-radius: 200px / 100px;
position: relative;
opacity: 0.5;
overflow: hidden;
float: left;
}
.int1:after{
background: black;
position: absolute;
content: '';
border-radius: 200px / 100px;
width: 400px;
height: 200px;
left: 240px;
}
.int1:hover{
transform: scale(1.3);
left: -35px;
}
.int2{
background: transparent;
width: 400px;
height: 200px;
border-radius: 200px / 100px;
position: relative;
opacity: 0.5;
overflow: hidden;
float: left;
left: 80px;
}
.int2:after{
background: black;
position: absolute;
content: '';
border-radius: 200px / 100px;
width: 400px;
height: 200px;
left: -240px;
}
.int2:hover{
transform: scale(1.3);
left: 115px;
}
HTML:
<div class="venn-container">
<div class="cat_one"></div>
<div class="cat_two"></div>
<div class="cat_three"></div>
<div class="int1"></div>
<div class="int2"></div>
</div>
And here is a fiddle: https://jsfiddle.net/y3Lvmuqg/2/
I would like the :hover to only get triggered in the intersections, and later make cat_one and cat_two hoverable outside the intersections.
I don't know if there is a way I'm doing this is the best and I'm open to suggestions.
Thanks for getting back to me #ge0rg I spent about an hour fiddling with CSS and HTML and came up with this code using just divs with background colors, hover events and border radius's (along with a few z-index and positioning techniques).
Hope you enjoy your reworked venn diagram...
You may have to mess around with the size, and definetly will have to mess with the positioning (however they're all inside a div and so it makes it so that you can just position the div and the rest will happen magically) I added a background color to the div just to show that nothing was transparent, and I also added a always on top function for viewing a section, and I hope you enjoy!
.Venn {
background: linear-gradient(to bottom right, blue, lightblue);
}
.d1:hover, .d2:hover, .d3:hover {
color: #565656;
animation: top 2s steps(2, end) forwards;
-webkit-animation: top 2s steps(2, end) forwards;
box-shadow: 0px 0px 20px white;
}
.d1, .d2, .d3 {
overflow-wrap: break-word;
}
.d1 center, .d3 center {
position: absolute;
top: 50%;
left: 50%;
transform: translateY(-50%) translateX(-50%);
}
.d1 {
padding: 10px;
width: 100px;
height: inherit;
z-index: 1;
position: absolute;
border-radius: 100%;
top: 0px;
}
.d3 {
padding: 10px;
width: 100px;
height: inherit;
z-index: 2;
position: absolute;
border-radius: 100%;
top: 0px;
left: 81px;
}
.d1:hover, .d3:hover {
transform: scale(1.05);
}
.d2 {
border-radius: 100% 0;
height: 90px;
width: 87.5px;
transform: rotate(-45deg) scale(.7);
position: absolute;
top: 15px;
left: 55.35px;
z-index: 3;
border: 1px solid black;
}
.d2b {
transform: rotate(45deg);
padding: 0;
margin: 0;
}
.d2b center {
position: relative;
left: 20px;
}
.d2:hover {
transform: rotate(-45deg);
}
.Venn {
height: 100px;
}
-webkit #keyframes top {
99% {
z-index: previous;
background-image: none;
}
100% {
z-index: 7;
}
}
#keyframes top {
99% {
z-index: previous;
background-image: none;
}
100% {
z-index: 7;
}
}
<div class="Venn" style="position: relative; left: 50px; width: 300px; height: 100px;">
<div class="d1" style=" background-color: grey;">
<center> 1 </center>
</div>
<div class="d2" style=" background-color: #AAAAAA;">
<div class="d2b" style="max-width: inherit;">
<center> 2 </center>
</div>
</div>
<div class="d3" style=" background-color: lightgrey;">
<center> 3 </center>
</div>
</div>
For those of you who would prefer a JSfiddle/ CodePen here you go a Codepen.
I am trying to animate height property of an element using CSS but I want it from the center. Below is my code but it changes height from bottom.
.toggle {
position: absolute;
width: 400px;
height: 200px;
background: #ccc;
}
.left-border {
position: absolute;
top: 50px;
left: 10px;
width: 20px;
height: 60px;
border-radius: 200px;
background-color: #ff0000;
animation: height 2s;
}
#-webkit-keyframes height {
from {
height: 60px;
}
to {
height: 10px;
}
}
<div class="toggle">
<div class="left-border"></div>
</div>
Here is JSFIDDLE
You can use transform
from {
}
to {
transform: scaleY(0.1666);
}
0.1666 comes from 10px / 60px
Here you go. I use animation top instead of height. The red toggle also needs a 'container' now so I just used the one you had there. When changing the dimensions of the red toggle, change the outer wrapper, not the toggle element (it will fit to whatever the container is, both width and height wise)
https://jsfiddle.net/j2refncs/7/
.toggle {
width: 20px;
height: 40px;
background: #ccc;
position: relative;
.left-border {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
border-radius: 200px;
background-color: #ff0000;
animation: height 2s;
}
}
#-webkit-keyframes height {
from {
top: 0;
}
to {
top: 30px;
}
}
Just add top: 75px to the keyframe since the change in height is 50px. You want to reduce the height by 25px or half from both sides, top and bottom, to come to the desired 10px. So 50px / 2 + top: 50px = top: 75px:
.toggle {
position: absolute;
width: 400px;
height: 200px;
background: #ccc;
}
.left-border {
position: absolute;
top: 50px; /* starting position from the top */
left: 10px;
width: 20px;
height: 60px;
border-radius: 200px;
background-color: #f00;
animation: height 2s;
}
#-webkit-keyframes height {
to {height: 10px; top: 75px} /* + ending position from the top */
}
<div class="toggle">
<div class="left-border"></div>
</div>
You can animate the top with the height to make the height change appear from the center:
.toggle {
position: relative;
width: 400px;
height: 200px;
background: #ccc;
}
.left-border {
position: absolute;
top: 25px;
left: 10px;
width: 20px;
height: 60px;
border-radius: 200px;
background-color: #ff0000;
animation: height 2s forwards;
}
#keyframes height {
from {
top: 25px;
height: 60px;
}
to {
top: 50px;
height: 10px;
}
}
<div class="toggle">
<div class="left-border"></div>
</div>
You can also use transform: scaleY() in the animation. The default transform origin is the center.
.toggle {
position: relative;
width: 400px;
height: 200px;
background: #ccc;
}
.left-border {
position: absolute;
top: 25px;
left: 10px;
width: 20px;
height: 60px;
border-radius: 200px;
background-color: #ff0000;
animation: height 2s forwards;
}
#keyframes height {
from {
transform: scaleY(1);
}
to {
transform: scaleY(0.167);
}
}
<div class="toggle">
<div class="left-border"></div>
</div>