Here is a short codepen of a simple css animation that I'm struggling to work with. Code also below:
.navscroll {
width: 100%;
height: 100px;
padding: 5px;
overflow: hidden;
position: relative;
background-color: red;
}
.navscroll div {
position: relative;
width: 200px;
height: 100%;
line-height: 50px;
text-align: center;
background-color: blue;
opacity: 1;
border-radius: 5px;
transform: translateX(100%);
animation: navscroll 15s linear infinite;
}
#keyframes navscroll {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(-100%);
}
}
<div class="navscroll">
<div>Why arent these</div>
<div>Side by side</div>
<div>or sliding across the WHOLE navbar</div>
</div>
Its supposed to be a scrolling navbar of divs, but I'm having two issues:
The inner divs are stacking vertically, not horizontally...
The inner divs are scrolling across only a small percentage of the nav bar / outer div...
Ideally, if there were many divs in the navscroll div, only 5-6 of them would display anytime on the screen, although the navbar would always be scrolling and those other divs would make their way onto the screen eventually. (similar to stock tickers ticking across the top of the TV screen). Any help with this is appreciated, thanks!!
div is a block level element (means it has display: block; by default). These create a line break before and after themselves. Use display: inline-block; and make sure they align properly using vertical-align: middle;.
2nd problem: translateX(100%) here the percentage does not refer to the parent element, but to the div being animated.
.navscroll {
width: 100%;
height: 100px;
padding: 5px;
overflow: hidden;
position: relative;
background-color: red;
white-space: nowrap;
}
.navscroll div {
position: relative;
width: 200px;
height: 100%;
line-height: 50px;
text-align: center;
background-color: blue;
opacity: 1;
border-radius: 5px;
transform: translateX(100%);
animation: navscroll 15s linear infinite;
/* this does the magic: */
display: inline-block;
vertical-align: middle;
}
#keyframes navscroll {
0% {
left: 100%;
}
100% {
left: -100%;
}
}
<div class="navscroll">
<div>Why arent these</div>
<div>Side by side</div>
<div>or sliding across the WHOLE navbar</div>
</div>
As per your question about how to create a snippet here:
The inner divs are stacking vertically because the default styling for a div is display: block. Adding the styles display: inline-block; vertical-align: top; to your .navscroll div rules will set them side by side, aligned to their top edges.
The animation is starting in the middle, and not all the way to the right like you intend because of how transform: translate() works. transform refers to the object being transformed, not its parent. So, translating something 100% of it refers to the width of the object. Try animating the position, something like this instead:
#keyframes navscroll {
0% {
left: 100%;
}
100% {
left: -600px;
}
}
EDIT: Also, remove the initial transform: translateX(100%); and you can simply animate the left position to -600px (3x the width of the each block).
Related
I want to make divs which got backgrounds that have this 3d-effect while scrolling, that one can achieve with translateZ. In the end it should look like cutouts or windows and through them you can see the (background-)images.
edit: So, if you scroll through the page you can see those boxes/cutouts but the images inside them are moving slower while scrolling to create the effect that they are further away. end of edit
What I have in mind is to have one div for the cutout and then another div inside it for the background. So, i set it up and it didn't work. It turns out that the overflow: hidden; of the outer div somehow blocks the transform: translateZ(-5px) scale(1.05); of its child.
Here is what I have got so far:
body {
perspective: 100px;
transform-style: preserve-3d;
overflow-x: hidden;
overflow-y: scroll;
}
#artwork, #photos {
width: 800px;
padding: 0 50px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
}
.pic {
/*position: relative;*/
width: 200px;
height: 100px;
display: inline-block;
background: #aaa;
border-radius: 10px;
box-shadow: inset 0 10px 30px rgba(0,0,0,.3);
}
#artwork > * {
overflow: hidden;
}
.pic div {
position: absolute;
width: 200px;
height: 110px;
background: #660; /*couldn't put an image here*/
background-size: cover;
transform: translateZ(-5px) scale(1.05);
}
<section id="artwork">
<div class="pic"><div></div></div>
<div class="pic"><div></div></div>
<div class="pic"><div></div></div>
</section>
P.S.: I don't want to achieve the effect via JavaScript because it's not working smoothly on most computers.
edit n°2: my approaches so far:
- making extra tick borders to cover overlapping parts of the image divs; instead of using overflow: hidden >> parts are sometimes still overlapping on some screen sizes & it takes a lot of space
- creating a clip-path to use as overflow: hidden >> clip-paths also break the translateZ
- playing around with display and position on both outer and inner div >> only solutions without cutout
- Ztranslating the parent of the outer div further away and then bringing the outer div close again >> still blocked by the overflow: hidden;
I found a workaround, although it's a compromise because the border radius isn't working. I added thick borders in the background color to the outer divs and set the z-index of the inner divs to something negative.
body {
height: 200px;
perspective: 100px;
transform-style: preserve-3d;
overflow-x: hidden;
overflow-y: scroll;
}
#artwork {
width: 800px
padding: 0 50px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
}
.pic {
width: 200px;
height: 100px;
margin: -40px;
display: inline-block;
background: transparent;
border: 40px solid hsl(30, 50%, 90%);
box-shadow: inset 0 10px 30px rgba(0,0,0,.3);
}
.pic div {
position: absolute;
width: 200px;
height: 110px;
background: linear-gradient(135deg, rgba(240,183,161,1) 0%,rgba(140,51,16,1) 50%,rgba(117,34,1,1) 51%,rgba(191,110,78,1) 100%);
transform: translateZ(-5px) scale(1.05) translateY(-1vw);
z-index: -20;
}
#artwork div:nth-child(2) div, #photos div:nth-child(2) div {transform: translateZ(-5px) scale(1.05) translateX(-1.5vw) translateY(-1vw);}
#artwork div:nth-child(4) div, #photos div:nth-child(4) div {transform: translateZ(-5px) scale(1.05) translateX(1.5vw) translateY(-1vw);}
<br><br><br><br><br><br><br>
<section id="artwork">
<div class="pic"><div></div></div>
<div class="pic"><div></div></div>
<div class="pic"><div></div></div>
</section>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
that code snippet doesn't work here for some reason. For me however it works in the browser. It would be nice if someone could suggest another possible solution as this one works with only some screen sizes.
This is what i am trying to achive
i have :
#image1 {
position: absolute;
bottom: 0px;
align-self: auto;
background-color: #dc022e;
width: 340px;
height: 100px;
border-radius: 50% / 100%;
border-bottom-left-radius: 0;
/*transform: rotate(10deg);*/
border-bottom-right-radius: 0;
opacity: 0.8;
}
#image2 img {
width: 80%;
}
<div>
<div id="image2">
<img src="http://t1.gstatic.com/images?q=tbn:ANd9GcThtVuIQ7CBYssbdwtzZjVLI_uw09SeLmyrxaRQEngnQAked5ZB">
</div>
<div id="image1"></div>
</div>
Finally I don't know how to make it rotated and with the margins cut like in the picture
A Quick example of this would use a pseudo element and have the image set in the background.
div {
position: relative;
height: 300px;
width: 500px;
background: url(http://lorempixel.com/500/300);/*image path*/
overflow: hidden;/*hides the rest of the circle*/
}
div:before {
content: "";
position: absolute; /*positions with reference to div*/
top: 100%;
left: 50%;
width: 0;/*define value if you didn't want hover*/
height: 0;
border-radius: 50%;
background: tomato;/*could be rgba value (you can remove opacity then)*/
opacity: 0.5;
transform: translate(-50%, -50%);/*ensures it is in center of image*/
transition: all 0.4s;
}
/*Demo Only*/
div:hover:before {/*place this in your pseudo declaration to remove the hover*/
height: 100%;
width: 150%;/*this makes the shape wider than square*/
transform: translate(-50%, -50%) rotate(5deg);/*ensures it is in center of image + rotates*/
}
div {/*This stuff is for the text*/
font-size: 40px;
line-height: 300px;
text-align: center;
}
<div>HOVER ME</div>
Instead of nested elements, you can just use a pseudo element. This is placed at the bottom of the container div. For this to work, you need position:relative and overflow:hidden on the container div. Also, pseudo elements always need the content declaration.
To modify the border radius, you just play around with left | width | height of the pseudo element. You don't need any rotation.
Instead of hex color and opacity you can as well use the "new" color space rgba(r,g,b,a) where a is the opacity value.
For the passepartout you simply use the border declaration.
#image2{
position:relative;
border:10px solid #888;
overflow:hidden;
box-shadow:0 0 4px #aaa;
}
#image2::after {
content:"";
display:block;
position: absolute;
bottom: 0;left:-10%;
background-color: #dc022e;
width: 120%;
height: 60%;
border-radius: 100% 100% 0 0;
opacity: 0.8;
}
#image2 img {
width: 100%;
display:block;
position:relative;
}
<div id="image2">
<img src="http://t1.gstatic.com/images?q=tbn:ANd9GcThtVuIQ7CBYssbdwtzZjVLI_uw09SeLmyrxaRQEngnQAked5ZB">
</div>
You can just use position: absolute for your image and position: relative for your overlay, adjusting the top position and width according to your needs. Here's a Fiddle. Hope this helps!
Edit: Here's an updated version of the Fiddle demonstrating border and overflow properties on the img container. As CBroe mentioned, rotating a circle is probably not a good use of your time in this case. Also, I definitely agree that using a pseudo element is a much cleaner approach than nesting images.
As I was in the process of trying to make an animated figure (transitions on hover), I found out that the background of my <figure> is showing near the edges when I apply border-radius: 50% to it, even though my image should be taking up all available space.
For a quick demo that illustrates the problem, please look at http://codepen.io/anon/pen/KwMMKz
HTML
<figure>
<img src="http://placehold.it/400x400" alt>
<figcaption>Demo</figcaption>
</figure>
CSS
figure {
background-color: red;
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
position: relative; /* For caption */
}
img {
border-radius: 50%; /* Forced on image for smooth transition */
width: 100%;
transition: opacity 1s ease-out;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
}
figure:hover img {
opacity: 0;
}
figure:hover figcaption {
top: 50%;
}
Please note: I know that placing the background-color on figure:hover is a work-around, but I am more interested in the reason why this "jagged border"-like look is appearing.
My guess is that it has to do with AA rendering (or something related) of the browser and that it treats the <figure> element differently than a media element such as <img>, but I can't find any proof of this online. Is this a bug, is it a "feature", or is it something I can actually fix?
Lastly, I also know that I could have used transform: translateY(); here for the animation, but that's not part of my question so please don't provide it as an answer.
UPDATE 17/12 14:03
It appears that this issue is not exclusive to border-radius: 50%. The issue can occur when any wrapping element uses border-radius in combination with overflow: hidden, when the wrapper contains content that is equal or bigger than the wrapper's dimensions.
UPDATE 17/12 14:14
Neither the usage of overflow: hidden on the wrapper element, nor the usage of border-radius on the contained image (or any other child element) seem to be the cause of this as they can be interchanged and the pixelated edge will still appear.
This seems to indicate that this issue is solely caused by 2 DOM elements being in exactly the same place, when any sort of border-radius is applied to the wrapper element and the visible area of the child is limited to that of the parent's.
I've been having same issue and ended up using pseudo element instead of background, kinda like that:
figure::before {
content: '';
display: block;
background-color: red;
width: 400px;
height: 400px;
transform: scale(0.997);
border-radius: 50%;
}
This allowed me to create 'pseudo background' which I later shrinked a little bit with transform: scale(0.997); so it will be just the same size but a bit below visible edge. Of course in your case you would also need to position image absolutely so it is not pushed below by this ::before.
It appears that it is indeed a "feature" of how the browser handles border-radius to give a smooth edge to the rounded corners of a container. The image background is anti-aliased in the same way (but as it is transparent has no effect) as can be seen by setting the img background color.
When the border is anti-aliased it "bleeds" into the background to soften the edges and so you are seeing that around the image as a "jaggy" ring in much the same way you would see a corona around the moon during a full solar eclipse.
the issue is always there, whether the anti-aliased object is covered or not, if you were to draw a circle then anti-alias it, you would see the circle is marginally narrower than the anti-aliased version. Most anti-aliasing algorithms aggregate the surrounding pixels of the object rather than those contained within it.
To overcome it, you'd either need to make your image large enough to cover the space taken up by the anti-aliased edge or reduce the container such that the anti-aliased area is smaller than the image.
You could add a new tag with an opacity of 0 then have that fade in with the image fading out.
figure {
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
position: relative; /* For caption */
}
background {
background-color: red;
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
opacity: 0;
position: fixed;
z-index: 5;
transition: opacity 1s ease-out;
}
img {
border-radius: 50%; /* Forced on image for smooth transition */
width: 100%;
transition: opacity 1s ease-out;
position: relative;
z-index: 100;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
z-index: 10000;
}
figure:hover img {
opacity: 0;
}
figure:hover background {
opacity: 1;
}
figure:hover figcaption {
top: 50%;
}
<figure>
<background></background>
<img src="http://placehold.it/400x400" alt>
<figcaption>Demo</figcaption>
</figure>
Notice I added the background tag and removed background-color from figure
http://codepen.io/marczking/pen/KwMgaR
So after playing around (used background-image and pseudo-elements, changes nothing...) you notice that this light border is only visible if you apply round corners. So I am assuming here it has to do how the Browser renders the CSS, nothing wrong with the CSS-rules ^^)
<figure>
<figcaption>Demo</figcaption>
</figure>
figure {
background-color: red;
width: 400px;
height: 400px;
border-radius: 100px;
position: relative; /* For caption */
}
figure::before {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: url("http://placehold.it/400x400") no-repeat;
border-radius: 100px; /* Forced on image for smooth transition */
transition: opacity 1s ease-out;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
}
figure:hover::before {
opacity: 0;
}
figure:hover figcaption {
top: 50%;
}
I have a div called main content, inside this div is another div called slideup. Using CSS animation, when you hover over the main content div, the slide up div slides up from the bottom to 50% height. This can be seen in my css code below
.maincontentdiv {
position: relative;
height: 100px;
width: 100%;
}
.slideup {
position: absolute;
width: 100%;
bottom: -2px;
min-height: 0;
color: #FFF;
transition: min-height 250ms ease-in;
background-color: #666666;
text-align: center;
height:20px;
}
.maincontentdiv:active > .slideup, .maincontentdiv:hover > .slideup {
min-height: 50%;
}
The hover works perfectly well, however I included the click function (.active) for touchscreen devices. I can not seem to get the click function working. Could somebody please tell me what I have done wrong?
Thanks
At the moment i am working on a header with a slider animation (css3 only):
http://jimmytenbrink.nl/slider/
Everything is working fine except sometimes the slider is bugging if you go from the center to the right. It seems that i need to stop the animation for a few miliseconds to complete. However i searched everywhere on the internet but i cant seem to get it to work.
Anyone here has experience with it who can help me out?
HTML
<header>
<div><span>slide 1</span></div>
<div><span>slide 2</span></div>
<div><span>slide 3</span></div>
<div><span>slide 4</span></div>
<div><span>slide 5</span></div>
<div><span>slide 6</span></div>
<div><span>slide 7</span></div>
<div><span>slide 8</span></div>
</header>
CSS
header {
margin-top: 10px;
width: 800px;
overflow: hidden;
height: 500px;
}
header div {
background-color: #000;
width: 43.8px;
height: 200px;
position: relative;
float: left;
-webkit-transition: width .3s;
transition: width .3s;
overflow: hidden;
-webkit-animation-timing-function: linear;
-webkit-animation-iteration-count: 1;
-webkit-animation-fill-mode: forwards;
margin-right: 2px;
}
header div:first-child {
margin-left: 0px;
}
header div:last-child {
margin-right: 0px;
}
header div:hover span {
left: 50px;
opacity: 1;
}
header div img {
position: relative;
left: -240px;
-webkit-transition: all .3s;
transition: all .3s;
-webkit-filter: grayscale(1);
overflow:hidden;
}
header div span {
-webkit-transition: left .3s;
transition: left .3s;
position: absolute;
bottom: 30px;
color: white;
left: -350px;
opacity: 0;
width: 450px;
font-family:'Fugaz One', cursive;
text-transform: uppercase;
font-size: 24px;
color: #fff;
text-shadow: 0px 0px 10px #f1f1f1;
filter: dropshadow(color=#f1f1f1, offx=0, offy=0);
}
header:hover > div {
width: 43.8px;
}
header:hover > div:hover {
width: 150px;
}
Here is a JSFiddle
So the question is, how can i set a stop on the animation for a few miliseconds so the animation can finish before it gets triggered again?
Hope my question is clear!
(thanks for the edit)
One might call my answer a workaround. Maybe it is but according to my comment on ExtPro's answer - it is still completely pure CSS.
I decided to use display: table-cell since the table cell's width is distributed equally.
So, the CSS might look like this:
HINT: This is only a bunch of necessary CSS. All the code is in the jsFiddle
header {
width: 368px;
display: table;
overflow: hidden;
}
header > div {
width: 44px;
height: 200px;
position: relative;
-webkit-transition: width .3s;
transition: width .3s;
display: table-cell;
overflow: hidden;
}
header > div:hover {
width: 151px;
}
Fiddle
As you can see, we don't have to determine the width of all not-hovered divs. Actually, the problem came from that very CSS rule:
/* DON'T USE THIS RULE - IT'S THE RULE WHICH WAS BAD */
header:hover > div {
width: 43.8px;
}
You were changing the width of the divs on header:hover, so when the transition didn't manage to do its job in time, you came out with mouse pointing to the header but to non of the divs.
If I understand what you mean by 'bugging', what is happening is if you move the mouse quickly to the right, it traverses the currently open div and is left in an area which when that div collapses, does not contain (e.g. the mouse is not hovered over) the next one in order to expand it- namely the hover event of the following div(s) is/are not firing thus they do not expand. There wont be a CSS fix for this Im afraid as its browser related, you may want to replace with jQuery/JS.