CSS limited background repeat (multiple background images) - css

I am trying to make a cool background effect (with alpha transparency and rounded corners) for a drop-down menu with a single CSS entry.
I have a top cap (180 x 4 px), a bottom cap (180 x 20px) and a repeating middle (180 x 2px).
Here is my existing relevant CSS:
background-image: url('images/drop_top.png'), url('images/drop_bottom.png'), url('images/drop_middle.png');
background-position:left top, left bottom, 0px 10px;
background-repeat:no-repeat, no-repeat, repeat-y;
The problem is that the middle section which needs to be expandable/tilable is repeating all the way under the top and bottom caps--such that my rounded corners are now square because they have the repeating middle under them.
Is there some way to prevent the multiple backgrounds from overlapping??
Thanks in advance!

Background-origin and/or background-clip should do the trick. Just set top & bottom borders equal to the height of your cap graphics, then set drop_middle to background-clip:padding-box
EDIT: Here is a complete solution, but for a horizontal orientation:
http://jsfiddle.net/nGSba/
#box
{
display: inline-block;
margin: 1em;
padding: 9px;
border-left:9px solid transparent;
border-right:9px solid transparent;
background-image: url(http://s11.postimage.org/ufpdknvjz/left.png),
url(http://s11.postimage.org/6ng294tj3/right.png),
url(http://www.css3.info/wp-content/themes/new_css3/img/main.png);
background-repeat: no-repeat, no-repeat, repeat-x;
background-position: left top, right top, left top;
background-origin: border-box,border-box,padding-box;
background-clip: border-box,border-box,padding-box;
}
What got me stuck was the transparent on the border-color. The background will always go under the border, so if your border is solid the background will still be invisible.

Whatever your element is that you are applying the images to, try doing the following (I'll assume div for sake of illustration):
div {
background-image: url('images/drop_top.png'), url('images/drop_bottom.png');
background-position:left top, left bottom;
background-repeat:no-repeat, no-repeat;
position: relative;
}
div:after {
position: absolute;
top: 10px ; /* whatever your top image height is */
bottom: 10px; /* whatever your bottom image height is */
left: 0;
right: 0;
z-index: -1;
background-image: url('images/drop_middle.png');
background-position: left top;
background-repeat: repeat-y;
}

Related

Hovered background color change breaks simulated + display

I have a button with + and - symbols made with linear gradients and background size. If I add a hover state, just changing the color, the + and - effect doesn't work. Any idea why this happens?
This is the pen: https://codepen.io/miguelrivero/pen/gOraZaM
.AddToBagButton__decrease,
.AddToBagButton__increase {
background: linear-gradient(#2e8561, #2e8561) top left,
linear-gradient(#2e8561, #2e8561) top right,
linear-gradient(#2e8561, #2e8561) bottom left,
linear-gradient(#2e8561, #2e8561) bottom right;
background-repeat: no-repeat;
border: 13px solid #2e8561;
box-sizing: border-box;
border-radius: 50%;
&:hover {
background: linear-gradient(#215e45, #215e45) top left,
linear-gradient(#215e45, #215e45) top right,
linear-gradient(#215e45, #215e45) bottom left,
linear-gradient(#215e45, #215e45) bottom right;
border: 13px solid #215e45;
}
}
.AddToBagButton__decrease {
background-size: 100% calc(50% - .5px);
left: 0;
}
.AddToBagButton__increase {
background-size: calc(50% - 1px) calc(50% - .5px);
right: 0;
}
Any idea why this happens?
Because you are overwriting the background-size you specified for the buttons, by applying the changed gradient via the background shorthand property, which resets all individual background properties you did not specify, to their defaults. (.AddToBagButton__decrease:hover has a higher specificity, than .AddToBagButton__decrease.)
Make that
&:hover {
background-image: …
instead. (Gradients are considered images in CSS.)

Chrome leaves white space/gap in between when rendering multiple gradients

I'm reading book "CSS Secrets" from Lea Verou.
There is example with radial multiple gradients for round corners:
http://dabblet.com/gist/24484257bc6cf7076a8e
IE11, Edge and FF display it correctly as it was intended. But Chrome create strange borders inside of block.
I can't understand why. It's look like a bug. Can anybody explain this behavior, may be this is just a part of Blink specification?
div {
background: #58a;
background: radial-gradient(circle at top left, transparent 15px, #58a 0) top left,
radial-gradient(circle at top right, transparent 15px, #58a 0) top right,
radial-gradient(circle at bottom right, transparent 15px, #58a 0) bottom right,
radial-gradient(circle at bottom left, transparent 15px, #58a 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;
width:4em;
height:4em;
padding: 1em 1.2em;
max-width: 12em;
color: white;
font: 130%/1.6 Baskerville, Palatino, serif;
}
<div></div>
I don't have any official sources to back this answer (not as yet, I am trying to find and will add here if I manage to find) but I've seen similar issues in Chrome in the past and they seem to because of how the calculated values are rounded in Chrome. Rounding is being done here because background size is 50% in both X and Y axis and the calculated values for 50% are fractions. The calculation is provided as inline comments within the snippet below.
Blink/WebKit seems to round down the calculated value irrespective of whether it is above 0.5 or not. In this demo, the total height of the element is 124.8px and the width is 133.12px. So, the 50% values become 62.4px and 66.56px (which are getting rounded down to 62 and 66px). The third div in the snippet has these values set explicitly as the background-size and we can see how its output looks same as the first one (which has background-size: 50% 50%) and thereby proving the explanation.
When the values are thus rounded down, the actual area occupied by the background horizontally is 132px (which is 1.12px less than the actual width) and that vertically is 124px (which is 0.8px lesser than the actual height). Thus it leaves a gap in between.
This blog post by John Resig also gives some insight on how rounding is handled in browsers. As we saw, Blink/WebKit is rounding down whereas IE seems to be rounding it up. Rounding up means the calculated values would become 63px and 67px and this wouldn't visibly show any problems because the color on all sides are the same and so they just overlap and fill the space (Chrome also shows no issues when we explicitly set these values for background size - refer second div). Firefox seems to have a comprehensive rounding logic which seems to round up some while some other get rounded down in-order to completely fill space and hence shows no issues too.
div {
background: #58a;
background: radial-gradient(circle at top left, transparent 15px, #58a 0) top left,
radial-gradient(circle at top right, transparent 15px, #58a 0) top right,
radial-gradient(circle at bottom right, transparent 15px, #58a 0) bottom right,
radial-gradient(circle at bottom left, transparent 15px, #58a 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;
width:4em; /* 83.2px */
height:4em; /* 83.2px */
padding: 1em 1.2em; /* left/right padding = 24.96px, top padding = 20.8px */
max-width: 12em;
color: white;
font: 130%/1.6 Baskerville, Palatino, serif; /* font-size = 130% of 16px = 20.8px */
}
/* so,
total width = 83.2px + (24.96px * 2) = 133.12px (50% = 66.56px)
total height = 83.2px + (20.8px * 2) = 124.8px (50% = 62.4px)
*/
div:nth-of-type(2) {
background-size: 67px 63px;
}
div:nth-of-type(3) {
background-size: 66px 62px;
}
div{
display: inline-block;
margin: 10px;
}
<div></div>
<div></div>
<div></div>
This is not the case for just radial gradients, it happens with linear gradients also.
div {
background: #58a;
background: linear-gradient(red, red) top left,
linear-gradient(blue, blue) top right,
linear-gradient(green, green) bottom right,
linear-gradient(tomato, tomato) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;
width:4em; /* 83.2px */
height:4em; /* 83.2px */
padding: 1em 1.2em; /* left/right padding = 24.96px, top padding = 20.8px */
max-width: 12em;
color: white;
font: 130%/1.6 Baskerville, Palatino, serif; /* font-size = 130% of 16px = 20.8px */
}
/* so,
total width = 83.2px + (24.96px * 2) = 133.12px (50% = 66.56px)
total height = 83.2px + (20.8px * 2) = 124.8px (50% = 62.4px)
*/
div:nth-of-type(2) {
background-size: 67px 63px;
}
div:nth-of-type(3) {
background-size: 66px 62px;
}
div{
display: inline-block;
margin: 10px;
}
<div></div>
<div></div>
<div></div>
And also with images also.
div {
background: #58a;
background: url(http://lorempixel.com/100/100/animals/1) top left,
url(http://lorempixel.com/100/100/animals/2) top right,
url(http://lorempixel.com/100/100/animals/3) bottom right,
url(http://lorempixel.com/100/100/animals/4) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;
width:4em; /* 83.2px */
height:4em; /* 83.2px */
padding: 1em 1.2em; /* left/right padding = 24.96px, top padding = 20.8px */
max-width: 12em;
color: white;
font: 130%/1.6 Baskerville, Palatino, serif; /* font-size = 130% of 16px = 20.8px */
}
/* so,
total width = 83.2px + (24.96px * 2) = 133.12px (50% = 66.56px)
total height = 83.2px + (20.8px * 2) = 124.8px (50% = 62.4px)
*/
div:nth-of-type(2) {
background-size: 67px 63px;
}
div:nth-of-type(3) {
background-size: 66px 62px;
}
div{
display: inline-block;
margin: 10px;
}
<div></div>
<div></div>
<div></div>
Note: I've been wanting to post a self Q & A for documenting this behavior for quite sometime now, so thank you for asking :)

css background repeat-x, strech-y

I have a striped background with a gradient which I want repeated in x and stretched in y. I thought this would work:
background: url(bg.jpg) repeat-x;
background-size: auto 100%;
But it either stretches in y or repeats in x, never both at same time:
http://codepen.io/anon/pen/JCjEb
Edit: Note that I cannot simply repeat in y since the striped background also have a gradient (dark in bottom, lighter at top).
Instead of giving it width auto, give it the width of the image (36px).
http://codepen.io/thgaskell/pen/Bjsix
CSS
.c {
background-size: 36px 100%;
}
You can just use background: url(bg.jpg) repeat; without background-size. Here is the example.
The problem is that when you set the background-size to auto 100%, it's going to stretch the whole image proportionally, thus making the stripes too wide and distorted. Set the x part of the background-size to the width of the original image, and it won't stretch anymore.
.b {
background: url(http://img.photobucket.com/albums/v63/promisedyouheaven/stripe2.gif) repeat;
background-size: 35px 100%;
}
http://jsfiddle.net/BsAcY/
Try background: url(bg.png) center repeat-x;
Not sure about IE8 and below though, if that's a problem.
.a { background:
url(http://img.photobucket.com/albums/v63/promisedyouheaven/stripe2.gif)
repeat; display:block; width:500px; }
Is that what you need?
Try this
** HTML **
<div class="b"></div>
** CSS for bg image & gradient **
.b { /* unprefixed gradient for example only*/
background:
linear-gradient(to bottom, rgba(0,0,0,1) 0%,rgba(255,255,255,0) 100%),
url(http://img.photobucket.com/albums/v63/promisedyouheaven/stripe2.gif);
background-repeat:repeat;
}
div {
height: 300px;
width: 200px;
margin-right: 50px;
border:1px solid grey;
}
Codepen Example

Shadow line with images as vertical separator btw DIVs - how to place top and bottom images?

I'd like to have a thin "shadow" line between my DIVs, as separator. Since I'd like the shadow line to be thiner and with more opacity at the top and at the bottom, I have created 3 images: middle shadow, top shadow and bottom shadow. Problem: I don't know how to place the "top shadow" image at the top of "middle shadow" and "bottom" shadow at the bottom (without multiple DIVs). I'm attaching an image done in fireworks where you can see and example of the shadow line.Many tks
div#content-center {
overflow: hidden;
background: khaki;
background: transparent url('images/middle_shadow.png') repeat-y top left;
padding: 0px 0px 0px 50px;
}
You also might be abel to do this with the :before and :after psedo-elements. Read up on them here if you aren't familiar.
#content-center{
background: url('images/shadow_repeat.png') center right repeat-y;
}
#content-center:before,
#content-center:after{
content:'';
display:inline-block;
position: absolute;
background-repeat: none;
/*size these to be what you need*/
height:100px;
width:100px;
}
#content-center:before{
top:0;
background-image: url('images/shadow_top.png');
}
#content-center:after{
bottom:0;
background-image:url('images/shadow_bottom.png');
}
Give multiple backgrounds:
background: url('images/middle_shadow.png') top left, url('images/middle_shadow2.png') center left,url('images/middle_shadow3.png') repeat-y bottom left;

Can I make a color background take up only a % of an element without making an image?

If I want to have a blue bar in the background at the top of my webpage (so the body element's background), but I want it to be 100px in height and span the entire horizontal background... is there any way to do this without making a background image that is 100px with the color I want (and maybe 1px in width) and making it repeat-x?
Basically, rather than doing:
background: url("images/pagestripe.png") repeat-x;
I want to do this:
background: #FFCCFF 100px top left repeat-x;
Which would give me a 100px background of the color #FFCCFF that starts in the top left of the page and repeats horizontally.
Similarly, if I wanted it to repeat-y, it would make the 100px the width instead of the height.
The positioning markers can represent offsets...
Is this possible? Is there actual CSS code for what I am looking for? Perhaps I'm not far off...
You can do it using linear gradients:
body {
background-image: -moz-linear-gradient(top, blue 100px, transparent 0);
background-image: -o-linear-gradient(top, blue 100px, transparent 0);
background-image: -webkit-linear-gradient(top, blue 100px, transparent 0);
background-image: linear-gradient(top, blue 100px, transparent 0);
}
Edit: This is CSS3 only. For CSS2 you may try
body:before {
content: ' ';
display: block;
top: 0;
position: absolute;
height: 100px;
width: 100%;
background: blue;
}
You could make the bar a separate div and set a negative margin on it. Something like this:
<div id="bluebar"></div>
Content goes here...
And then in CSS:
div#bluebar {
background: #fcf; /* that's actually pink, but whatever... */
height: 100px;
margin-bottom: -100px;
}
I'd give a jsFiddle link, but they're apparently down for maintenance right now, so here's a simple static HTML demo instead.
Yes it can be done.
You can create a single full width element with the height and background color you desire.
Use CSS to position the element.
div#bluebar {
background: #acf;
display: block;
height:100px;
width:100%;
position: absolute;
top: 0px; /* however far from the top you would like it*/
left: 0px;
z-index: 10; /* or some other number that will place it below the appropriate elements */
}
Just be sure that the parent of #blubar does not have position:relative; set or it will position relative to the parent not the document.

Resources