4

I'm getting a weird issue trying to use multiple backgrounds. The basic effect I want to have is a gradient background on the edges and a transparent background in the middle. Here's the really basic code:

background: transparent, linear-gradient(45deg, #f06, yellow);
background-size:50% 50%, 100% 100%;
background-position: 50% 50%, 0 0;
background-repeat: no-repeat;

I'm using dabblet to play around with it. If I use that code I get nothing (I replaced transparent with green take make sure I'll be able to see it): http://dabblet.com/gist/5339331

However if I reverse the backgrounds (backgound: linear-gradient(45deg, #f06, yellow), green;) it works perfectly as expected, except of course it's in reverse: http://dabblet.com/gist/5339291

What's going on here? Why would it work one way and not the other? I also tried replacing the gradient with blue to make it simple and it just doesn't work: http://dabblet.com/gist/5339396

FYI I'm testing in Chrome 27 and I get a yellow ! with the warning Invalid property value.

EDIT: Here's a better (yet still broken) example of the effect I'm going for. In this example, there are four pieces, each with their own gradient background. Ideally I'd have one piece because

  1. it would allow for a gradient that looks right.

  2. this looks horrible and doesn't play well on mobile devices.

  3. it would be nice to avoid the extra fixed/absolute divs if possible

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
redbmk
  • 4,687
  • 3
  • 25
  • 49
  • In your fiddle are the gradients supposed to be semitransparent? Or I should ask: do you want the content to show above or below the gradients, and if above, do you want to keep them semitransparent or make them opaque? I have a solution to this that I was going to post last night but dabblet and GitHub were being stupid - I suppose I'd take jsFiddle's constant downtimes over dabblet's near-unusable editor UI any day. – BoltClock Apr 09 '13 at 05:46
  • The gradients are supposed to be semitransparent and over the text. Imagine a stained glass window, where the center piece is cut out, so you can clearly see everything in the middle and only kind of see the rest. I'd hope for the gradient part to be all one piece. Here's [a better example](http://jsfiddle.net/redEvo/FGcgY/1/) in that the pieces don't overlap, but I'm trying to get one gradient to cover all four pieces (or really to have one piece with a hole in the middle). – redbmk Apr 09 '13 at 06:51
  • That sounds tricky, but I think I have a solution. I'll post an answer with some explanation. – BoltClock Apr 09 '13 at 06:57
  • Sounds cool. Here's another [sorta solution](http://jsfiddle.net/redEvo/FGcgY/3/). The gradient looks right but the text is on top of the gradient instead of underneath. – redbmk Apr 09 '13 at 07:01
  • That was what I assumed was your desired effect since you were using a background in the first place :) Anyway I just posted my answer. Superimposing a white-white gradient seems like a clever technique though, I'm not sure why it hadn't crossed my mind earlier. – BoltClock Apr 09 '13 at 07:10
  • I tried a white/white background on top, but it didn't quite look right – redbmk Apr 09 '13 at 07:32

2 Answers2

2

As you may be aware, transparent is a color value and not an image value, just like blue. Since it's a color value, it must be specified last in the background shorthand, and only there, because only the base layer may have a background color. This is why Chrome's Web Inspector is reporting an invalid property value with what you have.

Unfortunately there isn't a way to use multiple backgrounds to specify a single background image and an area of it that's cut out (e.g. to reveal a see-through opening in the mid-section).

What you have on jsFiddle is a step, though. You can easily do away with the extra div elements altogether by adding ::before and ::after pseudo-elements to both html and body instead, so you have four pseudo-elements to work with. You'll also need to use background-size and background-position to adjust the gradient backgrounds appropriately so they look seamless.

Since you want the gradients to be semitransparent while remaining seamless, you need to prevent them from overlapping. This is easily accomplished by adjusting the offsets as well as background-size accordingly.

Here's the CSS I've used:

html::before, html::after, body::before, body::after {
    display: block;
    position: fixed;
    background: linear-gradient(45deg, rgba(255, 0, 0, 0.5), rgba(0, 255, 0, 0.5));
    content: '';
}

html::before, html::after {
    height: 25%;
    left: 25%;
    right: 25%;
    background-size: 200% 400%;
}

body::before, body::after {
    width: 25%;
    top: 0;
    bottom: 0;
    background-size: 400% 100%;
}

html::before { top:    0; background-position: top;    }
html::after  { bottom: 0; background-position: bottom; }
body::before { left:   0; background-position: left;   }
body::after  { right:  0; background-position: right;  }

jsFiddle preview (with borders to show how I've arranged the pseudo-elements)

You won't be able to do this with just one box, so yes, it may not perform well on mobile devices. If this doesn't work too well, then you may be able to use an SVG background to achieve this, or failing that, you may have to fall back to using traditional pre-rendered background images.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • I like the pseudo-element idea. It also seems to work better on mobile (the fixed divs seem to go wherever they want on Chrome for Android when resizing or changing orientation, but with these they seem to stick to the edges). However, the background still looks a little weird. I discovered `background-attachment:fixed` which solves the problem perfectly! I [modified the fiddle](http://jsfiddle.net/redEvo/FGcgY/6/) some more. It appears `background-attachment:fixed` doesn't work on Android's Chrome though. – redbmk Apr 09 '13 at 07:46
  • @redbmk: Hmm, I played with the settings on my fiddle and found that `background-size: 400%` (equivalent to `background-size: 400% auto`) behaves differently on Firefox versus other browsers. Changing it to `background-size: 400% 100%` seems to make it work consistently across all browsers without the need for `background-attachment: fixed`, so something is off about the way they handle `auto`. I updated my answer with the changes. – BoltClock Apr 09 '13 at 07:59
  • Oh, I see! Yeah that works _perfectly_ in Chrome and on Android. Kudos! Thanks for the help – redbmk Apr 09 '13 at 08:07
  • @redbmk: No problem! Or, actually, one problem: I just tested this in Opera, and while everything works correctly on page load and scroll, the pseudo-elements and backgrounds don't respond to resize events so it all breaks horribly once the window is resized... depending on your compatibility requirements (future versions of Opera will be using Blink), this may or may not be a showstopper! – BoltClock Apr 09 '13 at 08:08
  • Well I'm really just messing around - kind of a proof of concept. In reality, IE9 and below don't even support gradients from what I've seen, so there would have to be some kind of backwards compatibility there too. Cross-browser support would be nice though - maybe there's a way to use real (non pseudo-) elements to create the same effect without acting funky in mobile browsers. Of course if it's only broken in a browser that's getting a new engine soon anyway.... – redbmk Apr 09 '13 at 08:25
  • @redbmk: In that case, looks like you have nothing to worry about :) I mentioned SVG images in my edit, which IE9 does support. I'm not familiar with SVG, but if you can use it to create a gradient with the middle portion cut out, then that's IE9 well taken care of. – BoltClock Apr 09 '13 at 08:30
0

The CSS background shorthand property syntax is as follows:

background: background-color background-image background-repeat background-attachment, background-position

Note that there aren't any commas, so it's best not to use them, especially when separating background-color and background-image.

Using all this and going back to the original example: http://dabblet.com/gist/5340042

Alfred Xing
  • 4,406
  • 2
  • 23
  • 34
  • That dabblet looks like the second one I had, where it shows a green background on the edges and the gradient in the middle. I'm trying to get the exact opposite though - gradient on the edges and green in the middle. The CSS spec for the [background shorthand](http://www.w3.org/TR/css3-background/#the-background) says the comma separates background layers – redbmk Apr 08 '13 at 23:02
  • Building off your example, [it looks like](http://dabblet.com/gist/5341353) you can create a gradient (it could just go from green to green for example), but making it transparent shows through to the other background, rather than making the whole background invisible. However, I'd like to be able to see what's under the entire div, something like a window – redbmk Apr 08 '13 at 23:12
  • @redbmk `background-size` only affects background images - in this case the gradient. I would use CSS pseudo-selectors for that (see updated answer) – Alfred Xing Apr 08 '13 at 23:14
  • @AlfredXing, I'm not seeing an updated answer. Also, I've updated the question to show a better example of what I'm trying to achieve. It could be polished to look nicer but this is easier and gets the point across easier I think: http://jsfiddle.net/redEvo/FGcgY/ – redbmk Apr 08 '13 at 23:34
  • @redbmk Sorry about that. This is what I go so far: http://jsfiddle.net/FaEK9/ but I have no idea how to get to where you want... I'm thinking it would be way easier to just use an actual image (it wouldn't take up much space/bandwitdth either) – Alfred Xing Apr 08 '13 at 23:50