6

I am trying to draw a decent diagonal with linear-gradient but I can't figure out how to do it when the container is small> I am trying to get a diagonal that fits inside a 10x10px container and looks like this:

enter image description here

This is my best attempt.

div {
  background: linear-gradient(50deg, transparent 4px, red 4px, red 5px, transparent 5px) no-repeat 0px 25px / 10px 10px;
  display:block;
  width:100px;
  height:100px;
}
<div></div>

What I am doing wrong?

Cain Nuke
  • 2,843
  • 5
  • 42
  • 65

3 Answers3

11

You can use a to [side] [side] linear gradient which is transparent except for the thickness of the diagonal like in the below snippet.

(Border is added only for demo and is not actually required for the gradient to work.)

div {
  display: block;
  width: 100px;
  height: 100px;
  border: 1px solid;
  margin: 10px;
}
.border-2px {
  background: linear-gradient(to bottom left, transparent calc(50% - 2px), red calc(50% - 1px), red calc(50% + 1px), transparent calc(50% + 2px)) no-repeat 0px 0px / 100px 100px;
}
.border-1px {
  background: linear-gradient(to bottom left, transparent calc(50% - 1px), red 50%, transparent calc(50% + 1px)) no-repeat 0px 0px / 100px 100px;
}
.border-1px.small {
  height: 10px;
  width: 10px;
  background: linear-gradient(to bottom left, transparent calc(50% - .5px), red 50%, transparent calc(50% + .5px)) no-repeat 0px 0px / 10px 10px;
}
.border-1px.small-2 {
  height: 10px;
  width: 10px;
  background: linear-gradient(to bottom left, transparent calc(50% - 1px), #EEE calc(50% - .5px), red 50%, #EEE calc(50% + .5px), transparent calc(50% + 1px)) no-repeat 0px 0px / 10px 10px;
}
.border-1px.small-3 {
  background: linear-gradient(to bottom left, transparent calc(50% - .5px), red 50%, transparent calc(50% + .5px)) no-repeat 0px 0px / 10px 10px;
}
.border-1px.small-4 {
  background: linear-gradient(to bottom left, transparent calc(50% - 1px), #EEE calc(50% - .5px), red 50%, #EEE calc(50% + .5px), transparent calc(50% + 1px)) no-repeat 0px 0px / 10px 10px;
}
<div class='border-2px'></div>
<div class='border-1px'></div>
<div class='border-1px small'></div>
<div class='border-1px small-2'></div>
<div class='border-1px small-3'></div>
<div class='border-1px small-4'></div>

Your approach was not wrong but it is better to avoid angular linear gradients when creating diagonals because angular linear gradients don't always produce diagonals. Depending on the dimensions of the container, the line that is produced can be a diagonal line (or) a line anywhere within the box. You can find more information about that in my answer here. Another advantage of using the to [side][side] gradients is that it is responsive.


If gradients don't work for you then you can have a look at using SVG but I don't think you can create lines with exact thickness as you need when it comes to diagonal lines. Diagonals are not as simple as straight lines to create.

div {
  position: relative;
  height: 100px;
  width: 100px;
}
svg {
  position: absolute;
  height: 10px;
  width: 10px;
  top: 0px;
  left: 0px;
}
path {
  stroke-width: 1.05;
  stroke: red;
  fill: none;
}
<div>
  <svg viewBox='0 0 10 10'>
    <path d='M0,0 10,10' />
  </svg>
</div>

A demo of how to use the SVG diagonal line as a background image is available here. SVG images can be layered on top of other background images also.

Community
  • 1
  • 1
Harry
  • 87,580
  • 25
  • 202
  • 214
  • To be fair, I can get the diagonal right with big containers but I cant with small ones like in my example. I need a diagonal that is 1px width across a 10x10px square but the line is either too wide or blurred. Can you make an example with a diagonal that small? Thank you. – Cain Nuke Jun 04 '16 at 12:02
  • Can you make it thinner as in the image I posted on my question? Thats exactly my issue. – Cain Nuke Jun 04 '16 at 12:17
  • No, you've got to use either the second last or the last. I think the last `div` in the snippet is the closest to the image in question (which I saw just now). If you try to make anything in between it would get blurred. That's how gradients work. – Harry Jun 04 '16 at 12:20
  • @CainNuke: I've added a slightly different variant for `.border-1px.small-4` and `.border-1px.small-2` by introducing another whitish color in between. It avoids blurs to an extent and looks slightly thicker than `.border-1px.small-1` but thinner than the original `.border-1px.small-4`. Check if it helps. I don't think there can be anything closer than this. – Harry Jun 04 '16 at 12:26
  • If thats the thinnest it can get then I guess gradients are not my best option to draw diagonals. I can draw straight lines with gradients which look perfect in any size but if diagonals really look this bad then I dont know what to use. – Cain Nuke Jun 04 '16 at 12:27
  • @CainNuke: For straight lines the pixels are directly below (or) to the side of another pixel but that's not the case for a diagonal line. I don't have any sources/links but I am pretty sure you can't do much more with gradients. Maybe you could try using SVG. – Harry Jun 04 '16 at 12:30
  • I've added a SVG sample as well, see if it helps (even though I think this is also not 100% as your image) @CainNuke. – Harry Jun 04 '16 at 12:35
  • Thanks for your kind help. SVG looks good but the problem is that I cant have them on the background. I am trying to draw a quite complex shape on the background of my container. I got all the straight lines right with linear gradients so now I just need to complete the diagonals but no luck. – Cain Nuke Jun 04 '16 at 12:46
  • @CainNuke: It would have been better had you specified that the exact thickness is a requirement in the question itself. It would have saved both of us some time on a weekend. Anyway, I don't understand why you can't use SVG because SVG's are images just like a gradient. I have used inline SVG just for demo (with positioning) but you can save the SVG as a separate file and use it via the background image tag also. If you're interested to know how, let me know and I'll try to give you a sample for that. Otherwise, I wouldn't bother spending time on that. – Harry Jun 04 '16 at 12:49
  • I am sorry about that. I didnt know thickness would change that much with small containers. About having a SVG as a separate file. Wouldnt that be the same as having a gif or jpg image as well? I am resorting to gradients because I want to avoid images as much as possible in order to keep the page load as fast as possible. – Cain Nuke Jun 04 '16 at 12:53
  • @CainNuke: SVG as separate file would be like GIF/JPG but not same (because SVGs are responsive). Plus a single SVG file whose size would hardly be a few KBs won't affect the page load speed. – Harry Jun 04 '16 at 12:57
  • Okay, then I guess I could give it a try and draw the whole shape as a SVG and then load it as the background of my container. – Cain Nuke Jun 04 '16 at 12:58
  • @CainNuke: Yes, that would be a good idea too. [Here](https://plnkr.co/edit/uTn0YYl0LRIO3MBnTNkY?p=preview) is how you can do just the diagonal line. I have set another radial-gradient background also to the same element just to show how it would work with multiple backgrounds. – Harry Jun 04 '16 at 13:03
  • @CainNuke: You're welcome. Happy that atlast we were able to atleast find something close to what you need! (Please don't forget to accept the answer if you really like the SVG version ;)). – Harry Jun 04 '16 at 13:07
  • Just one more question. In fill, can you have another png image or so to fill out the SVG image? – Cain Nuke Jun 04 '16 at 13:36
  • @CainNuke: You can but the SVG image in this case is only 10 x 10px. Do you want to fill only that small square (or) the larger container? If latter then it makes more sense to add it as background to the `div` itself. – Harry Jun 04 '16 at 13:39
  • If I am going to use SVG then I will quit gradients at all and draw the whole shape in SVG instead. I am asking this because I want the image filler to be contained within the SVG line borders instead of the square div container. – Cain Nuke Jun 04 '16 at 13:46
  • Can you show me an image of what you are looking for? Are you looking for a diagonal line and a fill for the triangle that is created on one side of the diagonal line? – Harry Jun 04 '16 at 13:47
  • @CainNuke: Check [this](https://jsfiddle.net/r1nkkczq/). The shape couldn't be created with lesser number of path elements because of your need for the stroke thickness to be same. This is the closest that I could achieve for the shape + fill. – Harry Jun 04 '16 at 14:20
  • 1
    Thats incredible. I think this is th solution to all my problems. Do you use any special tool to draw the SVG or do it manually? – Cain Nuke Jun 04 '16 at 14:22
  • @CainNuke: I do it manually because I am not a developer and so my objective is always to learn. But you can use tools like Illustrator, Inkscape etc. – Harry Jun 04 '16 at 14:24
  • Sorry again but I just noticed. When you use the SVG image as background the image fill wont load. Please check the new topic I just opened for the details. – Cain Nuke Jun 05 '16 at 05:03
  • @CainNuke: Have a look at this thread - http://stackoverflow.com/questions/6249664/does-svg-support-embedding-of-bitmap-images. You have to put the image as data URI instead of as a URL. – Harry Jun 05 '16 at 05:11
  • You mean as base64? – Cain Nuke Jun 05 '16 at 05:39
  • Yep @CainNuke. To be honest, I've never used that option much and so can't explain how to convert it to data URI. – Harry Jun 05 '16 at 06:33
  • I see. I was afraid of that. Its a major setback to learn that. It means SVG is useless to me after all because the filling image is way to big to encode and would make the SVG image file too large anyway. – Cain Nuke Jun 05 '16 at 06:44
1

You can use ::after pseudo class to do this.

div{
width:28px;
height:28px;
position:relative;}

div:after{
content:"";
position:absolute;
border-top:1px solid red;
  width:40px;
  transform: rotate(45deg);
  transform-origin: 0% 0%;
}
<div>
  </div>
Blazed
  • 199
  • 1
  • 1
  • 10
  • Thanks but that would not work in this case because I will have multiple linear-gradients on the same element and using rotate will rotate all of them which is not what I intend. Is it impossible to achieve a single diagonal line only with linear-gradient? – Cain Nuke Jun 04 '16 at 09:14
0

White line

direction: top,left => bottom,right

.line {
  background: linear-gradient(
    45deg,
    transparent,
    transparent 45%,
    #fff 45%,
    #fff 55%,
    transparent 55%,
    transparent 100%
  );
}
Jan Hrdý
  • 11
  • 2