Linear gradient percentages vs pixels - css

I have two examples, both of which to my knowledge should be identical.
The percentages are calculated based on the width which is 960px;
Here's the pixel version, which seems to work great.
.pixel {
background-color: #111111;
background-image: linear-gradient(90deg, transparent 40px, #444 20px );
background-size: 60px, 950px;
background-position: 10px, 10px;
}
However the identical percentage based gradient doesn't work:
.percentage {
background-color: #111111;
background-image: linear-gradient(90deg, transparent 4.1666%, #444 2.08333%);
background-size: 6.25%, 98.95833%;
background-position: 1.04167%, 1.04167%;
}
I want to use percentages so that this gradient is fluid when the container shrinks size.
DEMO: http://jsfiddle.net/shannonhochkins/A3Z2L/3/

It looks like the percentages inside the linear-gradient are expected to add up to 100%.
Your second example is saying "within the 6.25% (60px) of the background-size, the first 4.1666% is transparent and the next 2.08333% is gray", but you're not specifying what color the remaining 93.75007% of that 60px should be. (It looks like it just uses the last color for the remaining space, so within your 60-px background-size, you've got 4.1666% transparent and the remaining 95.8334% gray.)
Given that your proportions are 66%/33% in your first example, your second example should be using linear-gradient(90deg, transparent 66.6667%, #444 33.3333%).

The percentage in background-image isn't based on 1000px. It's based on the background size. In this case you want 66.6% of 60px.
.percentage {
background-color: #111111;
background-image: linear-gradient(90deg, transparent 66.6666%, #444 2.08333%);
background-size: 6.25%, 98.95833%;
background-position: 1.04167%, 1.04167%;
}

Related

Angled gradient with top offset by specific number of pixels

I'm trying to make a gradient that, for branding purposes, must be (1) at a specific angle, and (2) the top of it must be inset by a specific amount:
The rest of the proportions don't matter. I created this gradient like this:
background: linear-gradient(75deg, white 0%, black 30%, blue 30%, white 100%);
This only produces the correct top inset at specific client area height/widths. At other sizes, offset can be different:
Again, for branding reasons, this is unacceptable. That top of that slope must be inset by a specific amount.
I tried use a pixel value for the inset, e.g.
background: linear-gradient(75deg, white 0%, black 125px, blue 30%, white 100%);
This works... for the bottom of the slope. The bottom will be offset by 125px at any shape/size:
I'd like to do the same thing but have the top offset fixed to 125px.
You can approximate it using pseudo element and rotation. You consider a straight gradient (90deg) then you rotate it by adjusting the transform-origin to have the distance you want on the top:
.box {
height:300px;
position:relative;
overflow:hidden;
}
.box:before {
content:"";
position:absolute;
/* a random big value for top bottom and left*/
top:-500px;
bottom:-500px;
right:0;
left:-500px;
/**/
/* in the below 625px = 125px + 500px and adjust the 350px to get close to the gradient you wnat*/
background: linear-gradient(90deg, white 350px , black 625px, blue 0, white);
transform:rotate(-15deg);
transform-origin:625px 500px;
}
<div class="box">
</div>

Draw background with white dots with CSS3

I know it's possible to draw this background using only CSS (so without making use of image files). I'm curious on how I can do this. I've found a lot of information about making gradients and such with CSS3 on the web, but I've never found any guide that explains how to create something more advanced than this image as background in CSS. Any ideas on how to get started?
Not my fiddle, but I found this: http://jsfiddle.net/leaverou/RtGsM/
body {
background:
-moz-radial-gradient(white 15%, transparent 16%),
-moz-radial-gradient(white 15%, transparent 16%),
black;
background:
-webkit-radial-gradient(white 15%, transparent 16%),
-webkit-radial-gradient(white 15%, transparent 16%),
black;
background-position: 0 0, 80px 80px;
-webkit-background-size:160px 160px;
-moz-background-size:160px 160px;
background-size:160px 160px;
}

CSS : Positioning background gradient with fixed attachment at bottom right corner

I'm stuck on a CSS problem.
I would like to get a CSS stripe as background of my page like i did here, except that i want the stripe to be located on the bottom right corner of the page.
Moreover i want it to be a fixed background attachment.
I tried what is suggested here : How to position background image in bottom right corner? (CSS) but it seems to work only for background images and not for background gradients.
I tried changing offsets in the gradient definition but it's still relative to the top left corner, and the result would differ if the window size changes.
Here's my current code :
body
{
background: linear-gradient(
150deg,
rgba(180,214,14,0.0) ,
rgba(180,214,14,0.0) 70px,
rgba(180,214,14,0.4) 80px,
rgba(152,197,10,0.5) 150px,
rgba(0,0,0,0.4) 151px,
rgba(0,0,0,0) 160px
), no-repeat 0 0 !important;
background-attachment: fixed !important;
/* background-position: 80% 80% !important; */
background-repeat: no-repeat !important;
}
Any advice is welcomed !
I think you are correct, in that the background-position property only works for images and not gradients. At least that's what I'm finding by playing around with it.
So this isn't an answer to "how to make background-position work for gradients", but rather a suggestion to put your gradient on a different element and position IT to the bottom right.
Like:
div {
position: absolute;
right: 0;
bottom: 0;
width: 160px;
height: 160px;
background: linear-gradient(
150deg,
rgba(180,214,14,0.0) ,
rgba(180,214,14,0.0) 70px,
rgba(180,214,14,0.4) 80px,
rgba(152,197,10,0.5) 150px,
rgba(0,0,0,0.4) 151px,
rgba(0,0,0,0) 160px
), no-repeat 0 0;
background-position: center;
}
Granted, you'll probably have to change the gradient to fit better within that element, but I think this might be the only way to achieve what you're trying to do.
Also, you'll want to make sure that body has position: relative (or whatever the containing element is).

Using CSS alone, how can you have a Border-bottom gradient from Right to Left?

I would like to know if it is possible using CSS alone to be able to do a border-bottom with gradient going from right to left and not from the center outwards.
In my search for the answer, I have found a JSFiddle link which shows that it is possible to have a border gradient going from top to bottom which is transparent;
Method One
/* Using only background gradients */
.one {
width: 400px;
padding: 20px 25px;
border-top: 5px solid #000;
margin: 40px auto;
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#000), to(transparent));
background-image: -webkit-linear-gradient(#000, transparent);
background-image:
-moz-linear-gradient(#000, transparent),
-moz-linear-gradient(#000, transparent)
;
background-image:
-o-linear-gradient(#000, transparent),
-o-linear-gradient(#000, transparent)
;
background-image:
linear-gradient(#000, transparent),
linear-gradient(#000, transparent)
;
-moz-background-size:5px 100%;
background-size:5px 100%;
background-position:0 0, 100% 0;
background-repeat:no-repeat;
}
Method 2
/* Using pseudo-elements and background gradients */
.two {
position: relative;
width: 400px;
padding: 20px;
border: 5px solid transparent;
border-top-color: #000;
margin: 40px auto;
}
.two:before,
.two:after {
content: "";
position: absolute;
top: -5px;
bottom: -5px;
left: -5px;
width: 5px;
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#000), to(transparent));
background-image: -webkit-linear-gradient(#000, transparent);
background-image: -moz-linear-gradient(#000, transparent);
background-image: -o-linear-gradient(#000, transparent);
background-image: linear-gradient(#000, transparent);
}
.two:after {
left: auto;
right: -5px;
}
I do not understand how the above CSS is letting the page know the direction and I assume it is just a little, simple, under-looked edit, of which I cannot seem to find at this moment in time and therefore I am making this question to ask for some help.
I would also like to know if this will work if the border is dashed or dotted?
Thank you for any help and/or advice in advanced.
Best Regards,
Tim
NOTE - Edited the CSS to have the gradient span across the width of the element, not just the border width.
This is what I've come up with, which is more or less what h3n is suggesting with more vendor-specific properties filled-in:
border-right: 5px solid #000; /* Don't forget to modify to the right border. */
background-image:
-webkit-gradient(linear, 0 0, 0 100%, from(#000), to(transparent));
background-image:
-webkit-linear-gradient(180deg, #000, transparent),
-webkit-linear-gradient(180deg, #000, transparent)
;
background-image:
-moz-linear-gradient(180deg, #000, transparent),
-moz-linear-gradient(180deg, #000, transparent)
;
background-image:
-o-linear-gradient(180deg, #000, transparent),
-o-linear-gradient(180deg, #000, transparent)
;
background-image:
linear-gradient(90deg, #000, transparent),
linear-gradient(90deg, #000, transparent)
;
-moz-background-size: 100% 5px; /* This get flipped. */
background-size: 100% 5px; /* This get flipped. */
background-position: 0 0, 0 100%; /* The last argument gets flipped. */
background-repeat: no-repeat;
http://jsfiddle.net/vqnk9/1548/
MDN has a reasonable tutorial on how to handle this cross-browser, as well.
Now, if you look closely, you may notice that the non-vendor background-image uses 90deg instead of 180deg. My original thought was -90deg, so of course that makes sense to me somehow (?), but as to why they are different, here is the W3 spec (see the last quote for the reasoning behind this difference):
4.1.1. linear-gradient() syntax
The linear gradient syntax is:
<linear-gradient> = linear-gradient(
[ [ <angle> | to <side-or-corner> ] ,]?
<color-stop>[, <color-stop>]+
)
<side-or-corner> = [left | right] || [top | bottom]
The first argument to the function specifies the gradient line, which gives the gradient a direction and determines how color-stops are positioned. It may be omitted; if so, it defaults to ‘to bottom’.
The gradient line's direction may be specified in two ways:
using angles
For the purpose of this argument, ‘0deg’ points upward, and positive angles represent clockwise rotation, so ‘90deg’ point toward the right.
using keywords
If the argument is ‘to top’, ‘to right’, ‘to bottom’, or ‘to left’, the angle of the gradient line is ‘0deg’, ‘90deg’, ‘180deg’, or ‘270deg’, respectively.
If the argument instead specifies a corner of the box such as ‘to top left’, the gradient line must be angled such that it points into the same quadrant as the specified corner, and is perpendicular to a line intersecting the two neighboring corners of the gradient box. This causes a color-stop at 50% to intersect the two neighboring corners (see example).
Starting from the center of the gradient box, extend a line at the specified angle in both directions. The ending point is the point on the gradient line where a line drawn perpendicular to the gradient line would intersect the corner of the gradient box in the specified direction. The starting point is determined identically, but in the opposite direction.
And from MDN, some administrivia on why the degrees differ (blame Apple?):
A last semantic curiosity still exists between the prefixed variants
and the unprefixed proposal. Following the initial Apple proposal, the
prefixed variants of the syntax all uses the an <angle> defined like
polar angles, that is with 0deg representing the East. To be coherent
with the rest of CSS, the specification defines an angle with 0deg
representing the North. To prevent sites using prefixed version of the
property to get suddenly broken, even when adapting to the otherwise
forward-compatible final syntax, they keep the original angle
definition (0deg = East). They will switch to the correct spec when
unprefixing the property. Also, as they aren't incompatible, Gecko
supports, prefixed, both the syntax with the to keyword and without.
Here again, the syntax without the keyword will be dropped when
unprefixing.
at least for webkit this sets the angle so its from right to left:
-webkit-linear-gradient(180deg, black, white)

Multiple background images positioning

I've got three background images, all of width 643px. I want them to be set out like so:
top image (12px height) no-repeat
middle image repeat-y
bottom image (12px height) no repeat
I can't seem to do it without getting them to overlap (which is a problem because the images are partially transparent), is something like this possible?
background-image: url(top.png),
url(bottom.png),
url(middle.png);
background-repeat: no-repeat,
no-repeat,
repeat-y;
background-position: left 0 top -12px,
left 0 bottom -12px,
left 0 top 0;
Your problem is that the repeat-y is going to fill the whole height, no matter where you position it initially. Thus, it overlaps your top and bottom.
One solution is to push the repeating background into a pseudo element positioned off of the container by the 12px at the top and bottom. The result can be seen here (the opacity in the demo is just to show that there is no overlap going on). Without opacity, see here. The relevant code (tested in CSS3 browsers: IE9, FF, Chrome):
CSS
div {
position: relative;
z-index: 2;
background: url(top.png) top left no-repeat,
url(bottom.png) bottom left no-repeat;
}
div:before {
content: '';
position: absolute;
z-index: -1; /* push it to the background */
top: 12px; /* position it off the top background */
right: 0;
bottom: 12px; /* position it off the bottom background */
left: 0;
background: url(middle.png) top left repeat-y;
}
If you needed or wanted IE8 support (which does not support multiple backgrounds), then you could put the top background in the main div, and put the bottom background in by using the div:after pseudo element positioned to the bottom of the container.
If you can add padding/borders to the block equal to the backgrounds you want to position without overlapping other block, you can use the background-clip & background-origin to position the top and bottom backgrounds over the paddings/borders, and the repeating background over the content/paddings+content.
Here is an example: http://dabblet.com/gist/2668803
For your code, you'll possibly need to add something like this:
padding: 12px 0;
background-clip: padding-box, padding-box, content-box;
background-origin: padding-box, padding-box, content-box;
or
border: solid transparent;
border-width: 12px 0;
background-clip: border-box, border-box, padding-box;
background-origin: border-box, border-box, padding-box;
And you'll get what you need. If you can't get the paddings/borders, the pseudo-element like ScottS mentioned would work perfectly.
Try do it like this:
background: url(PICTURE.png) left top no-repeat, url(PICTURE2.png) right bottom no-repeat, url(PICTURE3.jpg) left top no-repeat;
}
EDIT:
Was just an example, but here's the css with your css:
background: url(top.png) left 0px top -12px no-repeat, url(middle.png) left 0px top 0px repeat-y, url(bottom.png) left 0px bottom -12px no-repeat;
}
I actually found a simpler fix, because I was having this same issue with a horizontal navigation.
Rather than adding code like the other answers you just have to list it differently in your CSS. The center image that repeats needs to be listed last, not first or second.
In my code it looks like this:
background-image: url(../images/leftNav.gif), url(../images/rightNav.gif), url(../images/centerNav.gif);
background-position: left, right, center;
background-repeat: no-repeat, no-repeat, repeat-x;
to use backgroud-position with 2 arguments, must to Write in extended writing backgroud-position-x and backgroud-position-y
background-position-x: left 0;
background-position-y: top -12px, bottom -12px, top 0;
A radical but effective way to deal with this, if:
you want to apply backgrounds with no overlapping to a ":before"
the ":before" element as a known max height
&:before {
background: url('vertical-line.png') no-repeat 0px,
url('vertical-line-repeat.png') no-repeat 140px,
url('vertical-line-repeat.png') no-repeat 200px,
url('vertical-line-repeat.png') no-repeat 260px,
url('vertical-line-repeat.png') no-repeat 320px,
url('vertical-line-repeat.png') no-repeat 380px,
url('vertical-line-repeat.png') no-repeat 440px,
url('vertical-line-repeat.png') no-repeat 500px,
url('vertical-line-repeat.png') no-repeat 560px,
url('vertical-line-repeat.png') no-repeat 620px,
url('vertical-line-repeat.png') no-repeat 680px,
url('vertical-line-repeat.png') no-repeat 740px;
}
Here's a method that uses 3 div's for each of the Top, Middle, and Bottom images that are transparent to apply to your webpage.
Background wallpaper is optional.
Tested in modern browsers and is IE8 friendly.
This method allows you to treat the body element as it should be treated, i.e., your webpage markup does not need to be in a wrapper or containing element.
jsFiddle Example
jsFiddle Example with centered filled
Since the above example uses image place holder content that is without transparency for Top and Bottom images, you can verify markup works with transparency with this jsFiddle that uses mini transparent icons in repeat mode HERE.
The only (practical, non hair-threatening) way I see is do do that in Javascript, when the page has loaded, and when it is resized, with a canvas sized to fit the innerHeight and the 3 images: draw the first one once at the top, draw the second as many times as required to cover the remainder of the canvas, and draw the 3rd one at the bottom of the canvas. Position the canvas at 0,0 with a ridiculously negative z-index.
I had a go at it with 3 images (643 x 12, 100 and 12) and of course the first issue I saw is that the 3rd image is drawn over part of the last iteration of the 2nd image -- unless you have a window height of exactly 12+12+(p2.height*X), you'll have some overlap. But that's expected, right?
I think z-index will fix this because z-index only affects CHILD elements, meaning you can't mess up anything else on the page that uses z-index.
top and bottom images z-index:3;
middle image z-index:2; background-repeat:repeat-y;

Resources