3D-transforms, z-index and Safari - css

I know 3d-transforms and z-indexes don't work especially well together, but I'm having this issue (only in Safari) for which I'm hoping there's still a solution.
Basically, I have 2 elements on top of each other. The one in the "back" (with the lower z-index) is being rotated in 3d space. I would still however like the top element to be on top at all times.
.button {
padding: 10px 30px;
position: relative;
display: inline-block;
color: white;
cursor: pointer;
}
.button span {
position: relative;
z-index: 2;
}
.button:after {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border-radius: 10px;
background: red;
transition: transform .2s;
}
.button:hover:after {
transform: rotateY(30deg);
}
<div class="button">
<span>Text</span>
</div>
This works well in Chrome and Firefox (haven't tested IE yet), but in Safari the back element "cuts through" the top element, making half of the top element invisible.
I've tried setting transform:translate3d(0,0,0) to the top element and also transform-style:preserve-3d to the parent element, with no success.
I've seen other posts about this on here, but they all seem to be outdated and the solutions don't seem to work.
You can see a fiddle here: https://jsfiddle.net/6mtgts33/

Add following:
.button span {
display: inline-block;
transform: translateZ(100px);
}
https://jsfiddle.net/6mtgts33/2/
.button { padding:10px 30px; position:relative; display:inline-block; color:white; cursor:pointer; }
.button span { position:relative; display: inline-block; transform: translateZ(100px); z-index: 2; }
.button:after { content:""; position:absolute; left:0; top:0; width:100%; height:100%; border-radius:10px; background:red; transition:transform .2s; }
.button:hover:after { transform:rotateY(30deg); }
<div class="button">
<span>Text</span>
</div>
Actually you don't need z-index: 2 for Safari, but need it for Chrome still.
Haven't checked in other browsers.

transform: rotateY(30deg);
-webkit-transform: rotateY(30deg); //chrome and safari

Related

CSS animation for hover effect flickers, not properly showing in FF

thanks for reading and offering help.
I assume my CSS code shouldn't be too complicated, however, it does not behave the way I want.
Expected result: when hovering over the button, there is a background area "folding up" (no background color to dark background color).
Actual results:
Works in Chrome (Version 88.0.4324.146), however, there is a flicker to it, like it is rebuilding again and again. This happens especially when hovering coming from the top. Looks alright when doing it from the bottom and rather slow.
I also saw that it seems to not really work in FF (Dev Edition 86.0b9). Sometimes it pops up, but if it does, it only does so once. Refreshing the browser window is not helping either.
I already tried to have a <div> around it and apply the hover animation to it, to fix it with prefixes... so far I couldn't make it work (smoothly), the issue always persisted.
So, this is the code now, which can also be found in this codepen example
html:
<button class="btn">
click
</button>
CSS:
.btn {
height: 48px;
width: 200px;
text-align: center;
text-transform: uppercase;
border: none;
border-bottom: 1px solid steelblue;
position: relative;
color: steelblue;
background: transparent;
::before {
bottom: 0;
content: "";
height: 100%;
left: 0;
opacity: 0;
position: absolute;
right: 0;
z-index: -1;
}
&:hover,
&:focus {
animation: one 0.25s linear;
background-color: steelblue;
color: whitesmoke;
opacity: 1;
transform-origin: 50% 100%;
}
#keyframes one {
0% {
transform: perspective(1000px) rotateX(90deg);
}
100% {
transform: perspective(1000px) rotateX(0);
}
}
}
If this is a duplicate, it means I didn't find the helping answer yet, will be happy for any solutions and hints.
The problem also happens in Chrome. It happens because you are changing the perspective of the button, which will change its "bounding box".
So when you mouse over the bounding box the animation will change the bounding box, and then the mouse is not over the bounding box, so the animation stops, but then the mouse is over the bounding box again, so the animation starts, and so on.
To fix this, create a container around the button, and make the countainer change the button perspective, instead of the button changing the perspective itself. The container will retain its bounding box when yo do this:
.bcg {
display: flex;
justify-content: center;
align-items: center;
background: whitesmoke;
height: 100vh;
}
.btncontainer {
display: inline-block;
}
.btncontainer:hover .btn, .btncontainer:focus .btn {
animation: one 0.25s linear;
background-color: steelblue;
color: whitesmoke;
opacity: 1;
transform-origin: 50% 100%;
}
#keyframes one {
0% {
transform: perspective(1000px) rotateX(90deg);
}
100% {
transform: perspective(1000px) rotateX(0);
}
}
.btn {
height: 48px;
width: 200px;
text-align: center;
text-transform: uppercase;
border: none;
border-bottom: 1px solid steelblue;
position: relative;
color: steelblue;
background: transparent;
}
.btn::before {
bottom: 0;
content: "";
height: 100%;
left: 0;
opacity: 0;
position: absolute;
right: 0;
z-index: -1;
}
<div class="bcg">
<div class="btncontainer">
<button class="btn">
click
</button>
</div>
</div>

Width transform animation without hover ? CSS issue

I come back here looking for your wisdom. I have been working on a website and I did some css to make a width transform animation effect behind some text, and it works fine using hover, buuut I would like to have the same effect only with an automatic animation (with some delay that works with the scroll), but saddly I don't know how.
Any ideas ?
Thanks so much !
here the website:
http://231e47.com/accueil-cf/
The hover effect is on the text "we are here!"
Here my CSS:
<style>
.highlight { display: inline-block;
color: #343434;
text-decoration: none;
position: relative;
z-index: 0;
}
.highlight::after {
position: absolute;
z-index: -1;
bottom: 10px;
left: 0%;
transform: translateX(0%);
content: '';
width: 0px;
height: 43%;
background-image: linear-gradient(120deg, #48d1de 0%, #84fab0 180%);
transition: all 250ms;
}
.highlight:hover {
color: #343434;
}
.highlight:hover::after {
height: 43%;
width: 108%;
}
</style>
THANKS A LOT !

CSS Heart with Text within

I would like to put a name into a heart made with CSS. And I can't seem to figure out how to do it.
I have this code already:
#heart {
position:relative;
width:100px;
height:100px;
}
#heart:before,#heart:after {
position:absolute;
content:"";
left:50px;
top:0;
width:50px;
height:80px;
background:#F00000;
-moz-border-radius:50px 50px 0 0;
border-radius:50px 50px 0 0;
-webkit-transform:rotate(-45deg);
-moz-transform:rotate(-45deg);
-ms-transform:rotate(-45deg);
-o-transform:rotate(-45deg);
transform:rotate(-45deg);
-webkit-transform-origin:0 100%;
-moz-transform-origin:0 100%;
-ms-transform-origin:0 100%;
-o-transform-origin:0 100%;
transform-origin:0 100%;
}
#heart:after {
left: 0;
-webkit-transform:rotate(45deg);
-moz-transform:rotate(45deg);
-ms-transform:rotate(45deg);
-o-transform:rotate(45deg);
transform:rotate(45deg);
-webkit-transform-origin:100% 100%;
-moz-transform-origin:100% 100%;
-ms-transform-origin:100% 100%;
-o-transform-origin:100% 100%;
transform-origin:100% 100%;
}
When I try to write the name directly into the div: "#heart", it just puts the text behind.
Thanks in advance for any help!
add a span element
<span id="text">Love</span>
with css
#text{
position:absolute;
z-index:3;
margin-left:35px;
margin-top:25px;
color:white;
display:block;
}
see this fiddle http://jsfiddle.net/FH9S7/
You can apply z-index: -1 to the :before and :after elements. It will move the heart shapes behind the text without needing an extra div.
After that, you can play around a bit with the paddings or text-align to align the text inside the heart:
http://jsfiddle.net/GolezTrol/hYEb6/1/
PS: In my fiddle I changed the id to a classname. By doing so, you can easily recycle the styling to add multiple hearts to the page.
-edit-
Maybe you'll like this one. If you are going to use an extra element, it's a bit easier to make the heart flexible in size as well:
The HTML can be (using classes again, of course):
<div class="heart">
<div class="inner">
Test
</div>
</div>
The CSS is a little bigger, but scalable:
.heart {
/* The only thing needed to change the size, are these numbers: */
width:200px;
height:200px;
}
.heart .inner {
/* Here is the styling and positioning for your text */
padding-top: 20%;
font-size: 3em;
color: white;
font-weight: bold;
}
/* The rest is default, and doesn't need to be modified, unless you want to change background color or other 'heart' properties. */
.heart .inner {
box-sizing: border-box;
width: 100%;
height: 100%;
}
.heart {
position:relative;
text-align: center;
box-sizing: border-box;
}
.heart:after,
.heart .inner:before,
.heart .inner:after {
z-index: -1;
content: "";
display: block;
position: absolute;
background-color: #F00000;
}
.heart:after {
width: 60%;
height: 60%;
left: 20%;
top: 25%;
-webkit-transform:rotate(-45deg);
-moz-transform:rotate(-45deg);
-ms-transform:rotate(-45deg);
-o-transform:rotate(-45deg);
transform:rotate(-45deg);
border-radius: 0 30% 0 0;
}
.heart .inner:before,
.heart .inner:after {
width:58%;
height:58%;
-moz-border-radius:50%;
border-radius: 50%;
top: 5.5%;
}
.heart .inner:before {
left: 0;
}
.heart .inner:after {
right: 0%;
}
And here's the fiddle showing 3 hearts of different sizes: http://jsfiddle.net/GolezTrol/hYEb6/4/
If you want to use position:absloute, you can do it that way:
http://fiddle.jshell.net/y9e58/
<div id="abs">name</div>
#abs{
position:absolute;
top: 30px;
left:40px;
}

css hover pseudo class issue when "leaving hover"

I'm trying to create a zoomable map that works when the mouse hovers over the map image, similar to how the maps work on Flickr (see the map on the right side-bar - http://www.flickr.com/photos/grynch108/5926065001/in/photostream/).
By default the map is zoomed out, when the mouse hovers over the map, it zooms in, and when the mouse hovers in the center of the map, it zooms further to street level.
I want to achieve this purely using CSS if possible (no JavaScript). I have it mostly working (it zooms in when mouse hovers over, and zooms again when mouse nears the center), however, after the mouse nears the center and it zooms fully, it will not zoom out again unless the mouse leaves the element completely. I would like it to zoom to the second level when the mouse leaves the center area. I hope that makes sense.
Here is a JSFiddle of what I have working. http://jsfiddle.net/garethlewis83/ejvRh/
NOTE: The CSS is generated from SASS, so I've included my SASS code below.
aside.photo-sidebar {
margin-left:20px;
width:296px;
display: inline-block;
vertical-align: top;
div#photo-map {
position: relative;
a#map-zoom-out, a#map-zoom-in {
position:absolute;
height: 100px;
width: 300px;
top:0;
left:0;
}
a#map-zoom-out {
opacity: 1;
z-index: 10;
transition: all 0.25s ease;
&:hover {
opacity: 0;
}
}
a#map-zoom-in {
z-index: 5;
}
a#map-zoom-street {
height: 20px;
left: 140px;
opacity: 0;
position: absolute;
top: 40px;
width: 20px;
z-index: 20;
transition: all 0.25s ease;
&:hover {
opacity: 1;
img {
display: block;
}
}
img {
display: none;
margin: -40px 0 0 -140px;
}
}
}
}
If you would consider using background images you could do something like this:
<div class="marker" href="#">°</div>
<div class="mymap"></div>
CSS:
.mymap {
position:absolute;
width:4px;
height:16px;
padding:42px 148px;
background:url(http://maps.googleapis.com/maps/api/staticmap?center=40.70723,-73.998298&zoom=4&size=300x100&sensor=false);
z-index:1;
}
.marker{
position:absolute;
top:22px;
left:121px;
padding:20px 27px 15px;
background:none;
z-index:2;
color:red;
}
.mymap:hover {
background:url(http://maps.googleapis.com/maps/api/staticmap?center=40.70723,-73.998298&zoom=8&size=300x100&sensor=false);
}
.marker:hover + .mymap {
background-image:url(http://maps.googleapis.com/maps/api/staticmap?center=40.70723,-73.998298&zoom=14&size=300x100&sensor=false);
}
Note the use of the adjacent selector to do the final zoom.
jsfiddle
in Sass it would be pretty simple:
.mymap {
position:absolute;
width:4px;
height:16px;
padding:42px 148px;
background:url(http://maps.googleapis.com/maps/api/staticmap?center=40.70723,-73.998298&zoom=4&size=300x100&sensor=false);
z-index:1;
&:hover {
background:url(http://maps.googleapis.com/maps/api/staticmap?center=40.70723,-73.998298&zoom=8&size=300x100&sensor=false);
}
}
.marker {
position:absolute;
top:22px;
left:121px;
padding:20px 27px 15px;
background:none;
z-index:2;
color:red;
+ .mymap {
background-image:url(http://maps.googleapis.com/maps/api/staticmap?center=40.70723,-73.998298&zoom=14&size=300x100&sensor=false);
}
}
If you would use sprites instead of separate images, then you would also have all of the map images loaded with the first one already.

CSS clip corners?

Is there a simple way to style element like this?
Supposed to be used on a mobile so CSS3 is fully available. Can't think of a simple way. Images are out of question.
It has to be this blocky and there supposed to be a text within (this is a blocky 8-bit button)
This jumps off of feeela's beginnings, but it's different enough to warrant its own answer.
Rather than putting a colored block overly, it only adds red-colored elements, allowing background to show through. HOWEVER, to calculate it properly (so that they're square corners!) I had to set a fixed width height. There's probably some sort of wacky way to do this with percentages, but for proof of concept it was too headachey to contemplate. Since the requirement is for fixed height variable width, this should work.
The pseudo-elements need to have content or they will "collapse". The content can be empty, but that property needs to be set.
CSS:
/* main button block */
.button {
display:inline-block;
background: #f00;
position: relative;
line-height: 60px;
text-align: center;
padding: 0 20px;
height: 60px;
margin-left: 0.5em;
}
/* common background color to all */
.button, .button::before, .button::after {
background-color: #f00;
}
/* shared styles to make left and right lines */
.button::before, .button::after {
content: "";
position: absolute;
height: 50px;
width: 5px;
top: 5px;
}
/* pull the left 'line' out to the left */
.button::before {
left: -5px;
}
/* pull the right 'line' out to the right */
.button::after {
right: -5px;
}
​
Fiddle: http://jsfiddle.net/3R9c5/2/
How about this?
HTML:
<div class="block">(text goes here)</div>
CSS:
body {background:#1990D7;}
.block {background:#FF1200; line-height:52px; margin:8px auto; width:359px;
position:relative; text-align:center; font-weight:bold; color:yellow}
.block::before {display:inline-block; background:#FF1200; content:'';
position:absolute; top:4px; left:-4px; bottom:4px; width:4px;}
.block::after {display:inline-block; background:#FF1200; content:'';
position:absolute; top:4px; right:-4px; bottom:4px; width:4px;}
Edit: updated after the latest insights into the demands of the question.
You can insert each of that four blocky-corners by appending pseudo elements via ::before or ::after.
e.g.:
.button {
background: #f00;
position: relative;
}
/* corner top left */
.button::after {
position: absolute;
top: 0; left: 0;
width: 5px; height: 5px;
background: #00f;
}
/* corner top right */
.button::after {
position: absolute;
top: 0; right: 0;
width: 5px; height: 5px;
background: #00f;
}
/* corner bottom left */
/* … */
The CSS border-radius attribute
maybe this will help you. Or you can just add new class, "cadre" for example
.cadre
{
border-radius: 10px;
}
to your css file, then affect it to the div.
I don't think border-radius can accomplish that. This is the simplest way I can think of:
http://jsfiddle.net/DpLdt/
CSS:
body {
background:blue;
}
div#clipcorners {
width:500px;
height:200px;
background:red;
position:relative;
margin:100px auto;
}
span#a,span#b {
position:absolute;
width:10px;
height:180px;
top:10px;
background:red;
}
span#a {
left:-10px;
}
span#b {
right:-10px;
}
​
HTML:
<div id="clipcorners">
<span id="a">
</span>
<span id="b">
</span>
</div>​

Resources