Related
I'm trying to replicate the google map's marker that shows user facing direction. It has got a cone/light beam/flash light type of shape where it fades from a color to transparent.
When I google css shapes, this is one of suggested methods for creating a cone shape :
.cone {
height: 0;
width: 0;
border-left: 100px solid transparent;
border-right: 100px solid transparent;
border-top: 100px solid #07CAF3;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
}
<div class="cone"></div>
But because it's made of borders, I cannot apply a gradient to it.
Any ideas ?
Use conic-gradient combined with mask:
.box {
width:200px;
height:100px;
border-radius:50%;
background:conic-gradient(from -45deg at bottom,#0000, blue 1deg 90deg, #0000 91deg);
-webkit-mask:linear-gradient(#0000,#000);
}
<div class="box"></div>
OR a radial-gradient one and the conic applied to mask:
.box {
width:200px;
height:100px;
background:radial-gradient(farthest-side at bottom,blue ,#0000);
-webkit-mask:conic-gradient(from -45deg at bottom,#0000, #000 1deg 90deg, #0000 91deg);
}
<div class="box"></div>
The mask idea from #temaniafif is probably the best idea, but you could also have two background-images, and in the radial one play around with the color and the percentage offsets/opacities to get the effect you want:
div {
background-image: conic-gradient(transparent 0deg, transparent 45deg, white 45deg, white 315deg, transparent 315deg, transparent 360deg), radial-gradient(rgba(0, 0, 255, 0.5), rgba(0, 0, 255, 0.2) 30%, rgba(0, 0, 0, 0.1) 70%, transparent 80%);
background-size: 100% 100%;
width: 75vmin;
height: 75vmin;
border-radius: 50%;
}
<div></div>
It's easy to create a rainbow in CSS using linear-gradient.
#grad1 {
height: 200px;
background: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet, red);
}
<div id="grad1"></div>
But look at it! This gradient is aesthetically horrifying. It's streaky, there's ugly strips of pure colour where the endpoints meet, it doesn't loop very well, it's not smooth, and the colours clearly contrast against each other when they should seamlessly blend.
In short: it's a terrible gradient.
I'd like to find the perfect gradient. One that encompasses the rainbow in a slick, smooth way, one that doesn't leave any obvious bumps or visual tearing. Instead of a spiky mess, this gradient is a smooth curve.
Does this gradient exist?
You need to choose colors that will blend nicely together and more color steps.
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%);
.rainbow-box {
width: 80vw;
height: 200px;
border-radius: 5px;
background: linear-gradient(
90deg,
rgba(255, 0, 0, 1) 0%,
rgba(255, 154, 0, 1) 10%,
rgba(208, 222, 33, 1) 20%,
rgba(79, 220, 74, 1) 30%,
rgba(63, 218, 216, 1) 40%,
rgba(47, 201, 226, 1) 50%,
rgba(28, 127, 238, 1) 60%,
rgba(95, 21, 242, 1) 70%,
rgba(186, 12, 248, 1) 80%,
rgba(251, 7, 217, 1) 90%,
rgba(255, 0, 0, 1) 100%
);
}
<div class="rainbow-box"></div>
I made it using CSS gradient generator:
https://cssgradient.io/
You can get something that looks better by overlaying the individual red, green, and blue colours, trying to match the human colour cone sensitivities.
Here's an example, but it could be improved by adjusting some of the % numbers in the linear-gradients, and by having smother gradient shapes (currently triangles with cut-off tops).
<!DOCTYPE html>
<html>
<head>
<title>Rainbow</title>
<meta charset="UTF-8" />
<style>
* { box-sizing: border-box; }
.separate { width: 100%; height: 10em; }
.separate>* { width: 100%; height: 100%; margin-top: 1em; }
.overlay { width: 100%; height: 10em; filter: brightness(3); }
.overlay>* { width: 100%; height: 100%; position: absolute; }
.overlay>:nth-of-type(1) { opacity: 1; }
.overlay>:nth-of-type(2) { opacity: .5; }
.overlay>:nth-of-type(3) { opacity: .33; }
.overlay>:nth-of-type(4) { opacity: .25; }
.blue { background: linear-gradient(
90deg, rgb(0,0,256) 0%, rgb(0,0,256) 5%, rgb(0,0,0) 20% ); }
.green { background: linear-gradient(
90deg, rgb(0,0,0) 0%, rgb(0,256,0) 25%, rgb(0,256,0) 35%, rgb(0,0,0) 55% ); }
.red { background: linear-gradient(
90deg, rgb(0,0,0) 15%, rgb(256,0,0) 35%, rgb(256,0,0) 45%, rgb(0,0,0) 100% ); }
.blue2 { background: linear-gradient(
90deg, rgb(0,0,0) 65%, rgb(0,0,256) 95%, rgb(0,0,256) 100% ); }
</style>
</head>
<body>
<h1>Rainbow</h1>
<div class="overlay">
<div class="blue"></div>
<div class="green"></div>
<div class="red"></div>
<div class="blue2"></div>
</div>
<div class="separate">
<div class="blue"></div>
<div class="green"></div>
<div class="red"></div>
<div class="blue2"></div>
</div>
</body>
</html>
"Rainbow" or "Color wheel" is often referred to as Hue.
CSS has the hsl() function (stands for Hue, Saturation, Lightness).
To create the gradients, simply divide the 360 hue degrees by 12 main colors (= 30 deg. steps).
Apply increments on the Hue by 30 degrees:
#hue {
height: 40px;
background: linear-gradient(90deg,
hsl(0, 100%, 50%),
hsl(30, 100%, 50%),
hsl(60, 100%, 50%),
hsl(90, 100%, 50%),
hsl(120, 100%, 50%),
hsl(150, 100%, 50%),
hsl(180, 100%, 50%),
hsl(210, 100%, 50%),
hsl(240, 100%, 50%),
hsl(270, 100%, 50%),
hsl(300, 100%, 50%),
hsl(330, 100%, 50%),
hsl(360, 100%, 50%)
);
}
<div id="hue"></div>
I’m not a CSS programmer, but just using the linear gradient fill in MS Word/Excel/PowerPoint, I like to create my rainbow with just the following 4 RGB colors:
(255,0,0) ; (255,255,0) ; (0,192,255) ; (192,0,255).
That looks pretty good to me, and with very little effort! {See Images >>}
Another variation of the rainbow above is “Sunset over the Ocean”. (It will make a great background for a webpage). Start with the rainbow, replace the last (purple) color with the following dark blue one: (60,70,200). Then move the yellow slider right up against the light blue one (mine is at 60% and 61%). And that’s it! {See Image >>}
I managed to do it in CSS! :-) >>
.Rainbow-4Color-Mix
{ width:200px; height:350px;
background: linear-gradient(180deg,
rgba(255, 0, 0, 1) 0%,
rgba(255, 255, 0, 1) 33%,
rgba(0, 192, 255, 1) 66%,
rgba(192, 0, 255, 1) 100%);
}
.Gap {width:200px; height:50px; background-color:white;}
.Ocean-Sunset
{ width:200px; height:350px;
background: linear-gradient(180deg,
rgba(255, 0, 0, 1) 0%,
rgba(255, 255, 0, 1) 60%,
rgba(0, 192, 255, 1) 61%,
rgba(60, 70, 200, 1) 100%);
}
<div class="Rainbow-4Color-Mix"></div>
<div class="Gap"></div>
<div class="Ocean-Sunset"></div>
Just an idea: Instead of explicitly specifying all of the colors in the rainbow, you could just specify red, yellow, and blue. The colors should then just blend naturally.
Another idea: If you don't like these particular shades of yellow, red, and blue, you could try custom ones with RGB values. The basic idea is the same though with only using the three primary colors in the rainbow.
EDIT: You can add violet back in by adding red at the end.
#grad1 {
height: 200px;
background: linear-gradient(45deg, red, yellow, blue, red);
}
<div id="grad1"></div>
Why can't you create a checkered background using something like this?
background-color:#ccc;
background-image:linear-gradient(90deg, transparent 50%, #aaa 50%),
linear-gradient(90deg, #aaa 50%, #ccc 50%);
background-size:50px 50px,50px 50px;
background-position:0 0, 0 25px;
The idea is to layer the alternating colors on the bottom of a striped square. It doesn't work but it seems like it should.
Here is an exact replica of what a checkered background looks in a graphic design editor like Photoshop or Illustrator. (ALL CSS)
.checkered{
height: 240px;
background: -webkit-linear-gradient(45deg, rgba(0, 0, 0, 0.0980392) 25%, transparent 25%, transparent 75%, rgba(0, 0, 0, 0.0980392) 75%, rgba(0, 0, 0, 0.0980392) 0), -webkit-linear-gradient(45deg, rgba(0, 0, 0, 0.0980392) 25%, transparent 25%, transparent 75%, rgba(0, 0, 0, 0.0980392) 75%, rgba(0, 0, 0, 0.0980392) 0), white;
background: -moz-linear-gradient(45deg, rgba(0, 0, 0, 0.0980392) 25%, transparent 25%, transparent 75%, rgba(0, 0, 0, 0.0980392) 75%, rgba(0, 0, 0, 0.0980392) 0), -moz-linear-gradient(45deg, rgba(0, 0, 0, 0.0980392) 25%, transparent 25%, transparent 75%, rgba(0, 0, 0, 0.0980392) 75%, rgba(0, 0, 0, 0.0980392) 0), white;
background: linear-gradient(45deg, rgba(0, 0, 0, 0.0980392) 25%, transparent 25%, transparent 75%, rgba(0, 0, 0, 0.0980392) 75%, rgba(0, 0, 0, 0.0980392) 0), linear-gradient(45deg, rgba(0, 0, 0, 0.0980392) 25%, transparent 25%, transparent 75%, rgba(0, 0, 0, 0.0980392) 75%, rgba(0, 0, 0, 0.0980392) 0), white;
background-repeat: repeat, repeat;
background-position: 0px 0, 5px 5px;
-webkit-transform-origin: 0 0 0;
transform-origin: 0 0 0;
-webkit-background-origin: padding-box, padding-box;
background-origin: padding-box, padding-box;
-webkit-background-clip: border-box, border-box;
background-clip: border-box, border-box;
-webkit-background-size: 10px 10px, 10px 10px;
background-size: 10px 10px, 10px 10px;
-webkit-box-shadow: none;
box-shadow: none;
text-shadow: none;
-webkit-transition: none;
-moz-transition: none;
-o-transition: none;
transition: none;
-webkit-transform: scaleX(1) scaleY(1) scaleZ(1);
transform: scaleX(1) scaleY(1) scaleZ(1);
}
You can see a working example in my pen here
This implementation yields a checkered background on Chrome, Firefox and Safari:
body {
background-image:
linear-gradient(45deg, #000 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #000 75%),
linear-gradient(45deg, transparent 75%, #000 75%),
linear-gradient(45deg, #000 25%, #fff 25%);
background-size:100px 100px;
background-position:0 0, 0 0, -50px -50px, 50px 50px;
}
This style defines a four part background image. Each linear-gradient defines a black triangle. The triangles are shifted so that they align to form squares (two triangles each). The last linear-gradient defines the color of the other two squares (the negative space). The positioning of the third and fourth triangle is what makes it work. (They would otherwise be positioned on top of the other two similar styles.) See the result in the fiddles provided (for a better understanding replace #000 with four different colors and change #fff to transparent):
http://jsfiddle.net/1o0f34hp
Applied to a div:
http://jsfiddle.net/1o0f34hp/1
However there does seem to be some tearing along the edges between triangles in the Firefox. This artifact is referenced here:
background image, linear gradient jagged edged result needs to be smooth edged
I've also implemented this as a React styled-component as follows:
let dark = '#777';
let light = '#ccc';
export const Checkerboard = styled.div`
background-image: linear-gradient(45deg, ${dark} 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, ${dark} 75%),
linear-gradient(45deg, transparent 75%, ${dark} 75%),
linear-gradient(45deg, ${dark} 25%, ${light} 25%);
background-size: ${props => `${props.size} ${props.size}`};
background-position: 0 0, 0 0,
${props =>
`calc(${props.size} / -2) calc(${props.size} / -2), calc(${
props.size
} / 2) calc(${props.size} / 2)`};
`;
After a lot of playing around and trying to do this in other ways I actually understood what you wanted to do :-). And you were actually very close. You had one single problem: Both your gradients have 90deg, so they covered each other. Also there's no need for the background color since the gradient in the back does not have any transparency and it covers everything.
html {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
background-image:linear-gradient(0deg, transparent 50%, #aaa 50%),
linear-gradient(90deg, #aaa 50%, #ccc 50%);
background-size:50px 50px,50px 50px;
background-position:0 0, 0 25px;
}
Also see this great post for how to create a proper checkerboard: http://lea.verou.me/2011/02/checkerboard-pattern-with-css3/
I made this simplified version. Set color & size in root properties in CSS.
:root {
--checker-color-1: #abcedf;
--checker-color-2: #123456;
--checker-size: 20px;
--checker-gradient: linear-gradient(45deg, var(--checker-color-1) 25%, transparent 25%, transparent 75%, var(--checker-color-1) 75%);
}
body {
background-color: var(--checker-color-2);
background-image: var(--checker-gradient), var(--checker-gradient);
background-position: 0 0, var(--checker-size) var(--checker-size);
background-size: calc(var(--checker-size) * 2) calc(var(--checker-size) * 2);
}
<!DOCTYPE html>
<html>
<head>
<title>CSS Checkered Background</title>
<meta charset="utf-8">
</head>
<body>
</body>
</html>
Updates:
This snippet was derived from CSS Checkered Background which shows a few more options.
But I have also since learned a new way of achieving the same effect, but it uses SVG (as well as JavaScript to create the SVG) SVG Checkered Background. Each method though has its own caveats.
Here is another tweak on this design but on a bias.
Please note that the background-size is important to keep a smooth transition in this pattern.
html {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
background:repeating-linear-gradient(135deg, rgba(0,64,101,0.7) 40%, #004065 60%),
repeating-linear-gradient(45deg, rgba(0,80,126,0.7) 40%, #004065 60%);
background-size:12px 18px;
background-position: 0 0;
}
To change the color of the background, alter the second hex color in both repeating linear gradients.
Hope this helps someone
While the previous answers show that it is possible, in most cases it's probably better to use an actual background image.
A 10x10 PNG checker image is around 80 bytes.
That is 108 bytes base64-encoded, and 148 bytes for the complete CSS rule - less than the shortest pure-CSS solution.
A 2x2 PNG image is not much smaller, but needs additional CSS for scaling and rendering.
The best solution I came up with is to use conic-gradient(). This also avoids the artifacts produced by linear-gradient() with 45deg.
function setVar(name, value) {
document.getElementById('checkered').style.setProperty(name, value);
}
.checkered {
--color-1: #808080;
--color-2: #a9a9a9;
--size: 8px;
background-image: conic-gradient(var(--color-1) 25%, var(--color-2) 25%, var(--color-2) 50%, var(--color-1) 50%, var(--color-1) 75%, var(--color-2) 75%);
background-size: calc(var(--size)*2) calc(var(--size)*2);
}
input {
margin: 4px;
height: 32px;
box-sizing: border-box;
border: 2px solid lightgray;
border-radius: 4px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Checkered Background Image (Pure CSS)</title>
</head>
<body style="margin:0; width:100vw; height:100vh;">
<div id="checkered" class="checkered" style="width:100%; height:100%; padding: 20px; box-sizing:border-box; display:flex; align-items:start;">
<div style="background-color:white; padding:8px; border-radius:9px; display:flex;">
<input type="color" name="color-1" value="#808080" oninput="setVar('--color-1', this.value)">
<input type="color" name="color-2" value="#a9a9a9" oninput="setVar('--color-2', this.value)">
<input type="number" name="size" min="1" value="8" oninput="setVar('--size', this.value + 'px')">
</div>
</div>
</body>
</html>
I made a checkerboard pattern based on 10x10 squares in the Terminal with ImageMagick like this:
magick -size 10x10 xc:"gray(154)" xc:"gray(102)" +append \( +clone -flop \) -append -strip checkerboard.png
That looks like this:
Now, if I want the base64 representation I can do:
magick -size 10x10 xc:"gray(154)" xc:"gray(102)" +append \( +clone -flop \) -append -strip png:- | base64
That gives this:
iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAAAAACo4kLRAAAAH0lEQVQY02OcxQADZ+AsJgYsYKgIsiD8YTJInEShIAA1NwKQeKc4/QAAAABJRU5ErkJggg==
which is just 120 characters!!!
Then I can use that for the repeating background like this:
<div style="background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAAAAACo4kLRAAAAH0lEQVQY02OcxQADZ+AsJgYsYKgIsiD8YTJInEShIAA1NwKQeKc4/QAAAABJRU5ErkJggg==)">'
And if I put a red <img> with a gradient transparency, on that background, I get:
It probably requires a workaround, or extra elements to achieve, but I'll ask anyway.
I have a simple image. The image is split into two diagonally. The top is a solid color and the bottom is transparent. If I apply the following code, the background color fills in the transparency of the image. Is there a way to position the color or not have it show through where my image area is and instead just fill the remainder of the element?
#content:before {
position: absolute;
z-index: -1;
bottom: -35px;
content: "";
width: 35px;
height: 465px;
left: -35px;
background: #121314 url(library/images/content-fold-left.png) 0 bottom no-repeat;
}
Use CSS3 Gradients:
html, body {
height: 100%;
}
body {
background: -webkit-gradient(linear, 50% 0%, 50% 100, color-stop(100%, rgba(0, 0, 0, 0)), color-stop(100%, #fa8072));
background: -webkit-linear-gradient(top, rgba(0, 0, 0, 0) 100px, #fa8072 100px);
background: -moz-linear-gradient(top, rgba(0, 0, 0, 0) 100px, #fa8072 100px);
background: -o-linear-gradient(top, rgba(0, 0, 0, 0) 100px, #fa8072 100px);
background: linear-gradient(top, rgba(0, 0, 0, 0) 100px, #fa8072 100px);
}
Here is a demo.
You'll notice I used Sass and Compass. The different gradient syntaxes are a nightmare, but with Sass and Compass, all you have to write is:
body
+background(linear-gradient(top, rgba(0,0,0,0) 100px, salmon 100px))
And it will compile all the vendor prefixes and different legacy syntaxes for you.
I'm wanting to add a transparent black overlay to a button for it' :active state, so when you click it, it's the same gradient but with just an overlay of e.g. rgba(0,0,0,.3)
The way I thought this would work is (using webkit in this example):
background:rgba(0,0,0,.3), -webkit-linear-gradient(top, #fcfcfc 0%,#bababa 100%);
or without the comma, and the order reversed... but nothing shows up at all!
I'm not keen on adding another div to act as the overlay to do it, so is there a strictly CSS way to do this? I was thinking maybe it's a :before or :after pseudo class, but I don't have a clue how to use these!
Would really appreciate an answer, this has been bugging me for a long time.
You can't do that; rgba defines a colour, not an image. What you can do is use a gradient that's not a gradient:
background: -webkit-linear-gradient(rgba(0, 0, 0, .3), rgba(0, 0, 0, .3)), -webkit-linear-gradient(top, #fcfcfc 0%,#bababa 100%);
This is why I always specify background-image instead of using the shorthand when developing - it makes debugging easier.
You can do it with ::after pseudo-element.
First, you need to define the button CSS with position: relative and then use ::after with position: absolute, like this:
.button {
position: relative;
}
.button:active::after {
content: ' ';
position: absolute;
background: rgba(0, 0, 0, 0.3);
top: 0;
left: 0;
bottom: 0;
right: 0;
}
Live Fiddle demo
Think in Reverse
Set background-color: black and overlay the gradient with your colors converted from hex to rgba (initially set to 1 for alpha), then on :active fade the gradient to 0.7 (which will show 30% black) alpha.
See the fiddle.
button {
background-color: black;
background-image: -webkit-linear-gradient(top, rgba(252, 252, 252, 1) 0%, rgba(186, 186, 186, 1) 100%);
background-image: -moz-linear-gradient(top, rgba(252, 252, 252, 1) 0%, rgba(186, 186, 186, 1) 100%);
}
button:active {
background-image: -webkit-linear-gradient(top, rgba(252, 252, 252, .7) 0%, rgba(186, 186, 186, .7) 100%);
background-image: -moz-linear-gradient(top, rgba(252, 252, 252, .7) 0%, rgba(186, 186, 186, .7) 100%);
}