Background-size:100% is slightly less than 100% - html

Please consider the following HTML and CSS :
HTML
<ul class="test1">
<li><div>Lorem ipsum</div></li>
<li><div>dolor sit amet</div></li>
</ul>
<ul class="test2">
<li><div>Lorem ipsum</div>
</li><li><div>dolor sit amet</div></li>
</ul>
CSS
.test1 div {height:100px;}
.test2 div {height:200px;}
li
{
display: inline-block;
width:100px;
transition:background-position 0.2s ease;
background-image: linear-gradient(to bottom, rgba(255,255,255,0) 50%, #F60 50%);
background-size: 100% 200%;
background-position : top left;
}
li:hover{color: #fff;background-position: bottom left;}
cfr jsfiddle
With a background being 200% of the height, and the top 50% of that background being transparent, that would mean that without hovering, all we can see is a transparent background. However, with this configuration I still can see a slight orange (#F60) line at the bottom, that being the bottom color of my "gradient" background.
If I want to fix this, I must specify background-size in pixels, and in that case I need to put background size as being (element size + 1 px)*2 . Could someone explain what causes this ? This is quite a problem as I would like to use this effect on blocks of a non-fixed height so percentage height is mandatory...

So here is a more involved answer that uses CSS animations: DEMO
Basically, I created colored DIV elements that have a 0% height. On hover of the parent li they grow to 100% height. The tricky part was preventing the return (shrink) animation from playing on page load: solved this by applying a white background to the overlaying text and fading it out after the initial page load completes (hideinit animation).
Added some classes and another DIV to the HTML markup:
<ul class="test1">
<li><div class="text">Lorem ipsum</div><div class="orange"></div></li>
<li><div class="text">dolor sit amet</div><div class="orange"></div></li>
</ul>
The updated CSS:
* I left off the webkit vendor prefixed styles for brevity, they are included in the Fiddle
li {
float: left;
list-style: none;
width:100px;
height: 100%;
position: relative;
}
li:hover div.orange{
animation: grow 1s 1 forwards;
}
li div.orange {
position: absolute;
bottom: 0;
background: orange;
height: 0%;
width: 100%;
z-index: -1;
animation: shrink 1s 1 forwards;
}
li div.text {
padding: 5px;
width: 100%;
height: 100%;
animation: hideinit 1s 1 forwards;
}
#keyframes grow {
from {height: 0%;}
to {height: 100%;}
}
#keyframes shrink {
from {height: 100%;}
to {height: 0%;}
}
#keyframes hideinit {
0% {background: white;}
98% {background: white;}
100% {background: none;}
}

I know that other answers already suggested increasing the background-size height to 201%, and that you had issues with items larger than, lets say 300px, but I tried 202% and was able to increase the size of the div up to 900px with no orange line appearing.
So in summary:
li {
display: inline-block;
width:100px;
transition:background-position 0.2s ease;
background-image: linear-gradient(to bottom, rgba(255,255,255,0) 50%, #F60 50%);
background-size: 100% 202%;
background-position : top left;
}
Best of luck!

to remove the line at the bottom you are having add:
li{
background-attachment: fixed;
}
JSFiddle
In response to dreamgt's comment I added some extra time to the animation. From:
transition:background-position 0.2s ease;
To:
transition:background-position 0.5s ease;
New JSFiddle

increase the height by an additional 1%
li {
display: inline-block;
width:100px;
transition:background-position 0.2s ease;
background-image: linear-gradient(to bottom, rgba(255,255,255,0) 50%, #F60 50%);
background-size: 100% 201%; /* <----------- increased height to 201% */
background-position : top left;
}
DEMO

Related

How to set transition for 2 backgrounds in an element?

in this code:
#p1 {
background-image: url(backimgs/first/1.jpg), url(backimgs/first/2.jpg);
background-color: #05080d;
background-position: left top, left bottom;
background-size: 100% 35%, 100% 65%;
}
I want when the page shows up, first show backimgs/first/1.jpg then after 1 sec show backimgs/first/2.jpg. how can I do it?
You can't animate background-images. You can change it, but there won't be any smooth transition:
#p1 {
background-image: url(backimgs/first/1.jpg), url(backimgs/first/2.jpg);
background-color: #05080d;
background-position: left top, left bottom;
background-size: 100% 35%, 100% 65%;
animation: change-bg;
animation-duration: 1s;
}
#keyframes change-bg {
0% {
background-image: url(backimgs/first/1.jpg), url(backimgs/first/2.jpg);
background-size: 100% 35%, 100% 65%;
}
100% {
background-image: url(backimgs/first/2.jpg), url(backimgs/first/1.jpg);
background-size: 100% 65%, 100% 35%;
}
}
If you want a smooth transition - you can use ::before and ::after with a background and animate the opacity of them. Let me know with a comment if you need more info on this aproach, I'll edit the post and show, how it's done.
You mention 'transition' in the title so you will need to control the two parts of the background separately.
To enable this, this snippet removes the backgrounds from the element itself, instead putting them onto two pseudo elements. The before pseudo element having the first image as background and the after pseudo element having the second one.
Separating the components in this way means we can animate the opacities, the first pseudo element going from opacity 0 to opacity 1 in the first second.
Note however that a little hack has been added to ths snippet. As the animation on the before pseudo element is to happen on load then there needs to be some method of waiting for the background image to load before the animation starts else there is a danger it will be part way through, or even finished, before the image is actually available.
I do not know the wider context of how you are testing for load being complete so have just put a delay in here for demo purposes. You'll need to decide what to do to avoid this inital load situation.
* {
margin: 0;
padding: 0;
}
#p1 {
/* added for this demo */
display: inline-block;
width: 100vw;
height: 100vh;
position: relative;
}
#p1::before,
#p1::after {
content: '';
position: absolute;
z-index: -1;
width: 100%;
left: 0;
display: inline-block;
background-color: #05080d;
background-size: cover;
background-repeat: no-repeat no-repeat;
background-position: center center;
animation: fadein 1s linear;
animation-fill-mode: forwards;
opacity: 0;
}
#p1::before {
top: 0;
height: 35%;
background-image: url(https://picsum.photos/id/1018/1024/768);
animation-delay: 1s;
/* a hack to ensure it is loaded before start the animation */
}
#p1::after {
bottom: 0;
height: 65%;
background-image: url(https://picsum.photos/id/1015/1024/768);
animation-delay: 2s;
}
#keyframes fadein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<div id="p1"></div>

CSS: Animate Partial Linear Gradient Background [duplicate]

This question already has answers here:
How to Animate Gradients using CSS
(5 answers)
Closed 1 year ago.
I have a div where the background is divided as follows:
div {
width: 200px;
height: 50px;
background: linear-gradient(135deg, gray 0%, gray 70%, blue 70%, blue 85%, red 85%);
}
div:hover {
animation: animate .5s ease forwards;
}
#keyframes animate {
0% {
background: linear-gradient(135deg, gray 0%, gray 70%, blue 70%, blue 85%, red 85%);
}
100% {
background: linear-gradient(135deg, gray 0%, gray 50%, blue 50%, blue 75%, red 75%);
}
}
<div></div>
As you can see, I would like the stripes in the background to shift on hover (and, indeed, shift back on leave).
I saw all the tutorials suggesting to use background-size and background-position but as I need the proportions to actually change, I don't know that that is the solution here.
I'd like the gradient proportion to animate smoothly, instead of just clipping like they do in the above snippet.
As you have disovered, linear gradients as you have them don't animate.
One simple way of getting a similar but smooth effect is to use scale, which is animatable.
This snippet draws the linear-gradient on a pseudo element and transitions the scale on that, having put the transform origin to the bottom right hand corner. The div has overflow set to hidden.
div {
width: 200px;
height: 50px;
overflow: hidden;
position: relative;
}
div::before {
content: '';
position: absolute;
top: 0;
left: 0;
display: inline-block;
width: 100%;
height: 100%;
transform: scale(1);
transform-origin: right bottom;
transition: transform .5s ease;
background: linear-gradient(135deg, gray 0%, gray 70%, blue 70%, blue 85%, red 85%);
z-index: -1;
}
div:hover::before {
transform: scale(1.5);
}
<div>SOME CONTENT</div>
Take a look at the second and third answers from this post. By animating the opacity of two different gradients or using css variables alongside a transition, you should be able to get the desired result.
I've set up an example of the second method using your code:
#property --gb { /* grey/blue */
syntax: '<percentage>';
inherits: false;
initial-value: 70%;
}
#property --br { /* blue/red */
syntax: '<percentage>';
inherits: false;
initial-value: 85%;
}
div {
--gb: 70%;
--br: 85%;
width: 200px;
height: 50px;
transition: --gb 2s, --br 2s;
background: linear-gradient(135deg, gray 0%, gray var(--gb), blue var(--gb), blue var(--br), red var(--br));
}
div:hover {
--gb: 50%;
--br: 75%;
}
<div></div>

Only one CSS animation bar at any point of time

I am using CSS animation to show an indeterminate progress bar. Refer code below. If you'll notice there are 2 moving gradient at any point of time, i.e. when the 1st one reaches 50% of the width, 2nd one starts. I know that I have defined the css that way using webkit-background-size(50% and 100%). However what I am not able to do is make sure that there should be only 1 moving part at any point of time - i.e. once the animation reaches the right end of the div only then it should start it from the left end. Any pointers on this?
Refer https://jsfiddle.net/AnuragSinha/nuokygpe/1/ and corresponding code below.
#-webkit-keyframes moving-gradient {
0% { background-position: left bottom; }
100% { background-position: right bottom; }
}
.loading-gradient {
width: 200px;
height: 30px;
background: -webkit-linear-gradient(
left,
#e9e9e9 50%,
#eeefef 100%
) repeat;
-webkit-background-size: 50% 100%;
-webkit-animation-name: moving-gradient;
-webkit-animation-duration: 1s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
<div class="loading-gradient" style="width: 200px; height: 30px"> </div>
Instead of making the gradient 50% make it 200% and define 2 gradient coloration inside it. Doing so each part of the gradient will cover exactly 100% of the element width then you can animation it from left to right.
.loading-gradient {
width: 200px;
height: 30px;
background: linear-gradient(to left,
#e9e9e9 0% 25%, #eeefef 50%, /* first one take the half*/
#e9e9e9 50% 75%, #eeefef 100%); /* second one take the other half*/
background-size: 200% 100%;
animation: moving-gradient 1s linear infinite;
}
#keyframes moving-gradient {
0% {
background-position: right;
}
/*100% {
background-position: left; /* No need to define this since it's the default value*/
}*/
}
<div class="loading-gradient" style="width: 200px; height: 30px"> </div>
Since the gradient is now having a size bigger than the container, you need to do the opposite animation (from right to left).
More details: Using percentage values with background-position on a linear gradient
Here is another idea where you can consider pseudo element and translate animation:
.loading-gradient {
width: 200px;
height: 30px;
position:relative;
z-index:0;
overflow:hidden;
}
.loading-gradient:before {
content:"";
position:absolute;
z-index:-1;
top:0;
right:0;
width:200%;
bottom:0;
background: linear-gradient(to left, #e9e9e9 50%, #eeefef 100%);
background-size: 50% 100%;
animation: moving-gradient 1s linear infinite;
}
#keyframes moving-gradient {
100% {
transform: translate(50%);
}
}
<div class="loading-gradient" style="width: 200px; height: 30px"> </div>

Css button gradient background position [duplicate]

This question already has answers here:
Using percentage values with background-position on a linear-gradient
(2 answers)
Closed 2 years ago.
I used a button with a background effect. However, I don't understand how the background-position works.
the background position is set to the right then when I mouse over the button the background move to the left. However, I can't figure out why the "blue" seems to come from the left to the right, it's like if the background move to the right.
Shouldn't the background move to the left?
button {
color: white;
background: linear-gradient(to left, red 50%, blue 50%);
background-size: 200%;
background-position: right bottom;
border: none;
border-radius: unset;
width: 85px;
height: 35px;
transition: 2s ease;
cursor: pointer;
}
button:hover {
background-position: left bottom;
}
<button>Button</button>
Fiddle Link
The logic is simple, let's start by each property.
First you defined the gradient like this linear-gradient(to left, red 50%, blue 50%) which means that starting from the left we will have 50% of red then the remaining blue (50% too)
div {
height:50px;
width:100px;
background-image:linear-gradient(to left, red 50%, blue 50%)
}
<div>
</div>
Now you specified the background-size to be 200% which means that you will scale the size of the background by 2. To illustrate check the below code to see the intial background and the scaled one:
div {
height:50px;
width:100px;
background-image:linear-gradient(to left, red 50%, blue 50%)
}
div:nth-child(2) {
height:100px;
width:200px;
margin-top:20px;
}
<div>
</div>
<div>
</div>
But a background should always fit into the size of the element and in this case you will only see 1/4 of it (since we did a scale on both direction). And the background-position will decide about this. When you set it to right bottom you make the right bottom corner of the background to match the right bottom corner of the element like below:
So you will intially see the yellow part. And if you specify left bottom you will have this:
So it's like the yellow box is sliding from right to left OR the yellow box is fixed and the background is moving from left to right (this the behavior you see since the yellow box here is your button) .
The main reason about this movement is the overflow, so to change its position the background should move in the opposite direction unlike if the background-size was less than 100%. And if the background size was 100% you will see no movement because both position are equivalent!
Here is a working example with the 3 different cases:
div {
height:50px;
width:100px;
background-image:linear-gradient(to left, red 50%, blue 50%);
border:1px solid;
background-position:right bottom;
background-repeat:no-repeat;
transition:1s;
}
.d1 {
background-size:50%;
}
.d2 {
background-size:100%;
}
.d3 {
background-size:200%;
}
body:hover div{
background-position:left bottom;
}
I will move from right to left
<div class="d1">
</div>
I will not move !
<div class="d2">
</div>
I will move from left to right
<div class="d3">
</div>
Remove the background-position from your button or change the order like backgrond-position:left bottom and apply the right instead of left in your gradient and hover position like below.
button
{
color:white;
background: linear-gradient(to right, red 50%, blue 50%);
background-size: 200%;
border: none;
border-radius: unset;
width: 85px;
height: 35px;
transition: 2s ease;
cursor: pointer;
}
button:hover
{
background-position:right bottom;
}
Same I have added in the following snippet.
button
{
color:white;
background: linear-gradient(to right, red 50%, blue 50%);
background-size: 200%;
border: none;
border-radius: unset;
width: 85px;
height: 35px;
transition: 2s ease;
cursor: pointer;
}
button:hover
{
background-position:right bottom;
}
<button>
Button
</button>

How to clip animation outside of div using clip-path?

This is a followup question to the one I asked yesterday.
My goal was to create a box and slide an SVG graphic through the box, so that as the graphic moved, you would only see the parts of the graphic that were in the box, and the parts outside the box would be hidden. Here's the code that made that work:
HTML:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<br><br><br>
<div id="mydiv">
<br><br><br>
<a id="swipe1";><img src="https://www.benngrant.com/html5/shape1.svg" /></a>
<br><br><br><br>
</div>
</body>
CSS:
body {background: #ffffff url("https://www.benngrant.com/wp-content/themes/Abstract_Dark1/images/Bottom_texture.jpg") no-repeat center center fixed; background-size:cover;}
a#swipe1 {transition-timing-function:linear; position:relative; opacity:.62; top:10px; animation: mymove 7.85s forwards;}
#keyframes mymove{from {left:-100%;} to {left:150%;}}
#mydiv {text-align:center; background:black; opacity:.5; max-width:50%; position:relative; margin-left:auto; margin-right:auto; display:block; overflow: hidden; border:1px solid black}
Basically, all I had to do was add overflow:hidden and position:relative to #mydiv to make it work, which was pointed out. (I get why overflow:hidden is needed, still confused why position:relative is, but oh well.)
This time what I am asking is this: Is there an alternate way to accomplish the same effect using the clip-path css property to define a rectangle that hides any part of the moving graphic that is not within the rectangle? Can clip-path in fact be used somehow to define where the browser is permitted to draw the part parts of the image that are within it, as the image moves around following the keyframes? It seems reasonable to me in theory, but I'm not sure how to begin to implement it that way.
Any thoughts? Using just HTML and CSS, but not JavaScript? That creates a result equal to what this does?
https://jsfiddle.net/91p21odc/
Maybe something like this:
body {
background: #ffffff url("https://www.benngrant.com/wp-content/themes/Abstract_Dark1/images/Bottom_texture.jpg") no-repeat center center fixed;
background-size: cover;
}
#mydiv {
margin: 50px 0;
padding: 40px 0;
}
#swipe1 {
transition-timing-function: linear;
opacity: .62;
display: inline-block;
position: relative;
animation: mymove 7.85s forwards;
}
.clip {
clip-path: polygon(40% 0%, 60% 0%, 60% 100%, 40% 100%);
}
#keyframes mymove {
from {
left: -100%;
}
to {
left: 150%;
}
}
#mydiv {
text-align: center;
background: black;
opacity: .5;
max-width: 50%;
position: relative;
margin-left: auto;
margin-right: auto;
display: block;
overflow: hidden;
border: 1px solid black
}
<div id="mydiv">
<div class="clip">
<div id="swipe1">
<img src="https://www.benngrant.com/html5/shape1.svg" />
</div>
</div>
</div>