12

For some time already I've been using this to create corner ribbons and so far it always worked fine:

body {
  margin: 10%
}

img {
  border-radius: 0.5vw;
}

.picture {
  position: relative;
}

.ribbon {
  position: absolute;
  left: -5px; top: -5px;
  z-index: 1;
  overflow: hidden;
  width: 75px; height: 75px;
  text-align: right;
}
.ribbon span {
  font-size: 10px;
  font-weight: bold;
  color: #FFF;
  text-transform: uppercase;
  text-align: center;
  line-height: 20px;
  transform: rotate(-45deg);
  -webkit-transform: rotate(-45deg);
  width: 100px;
  display: block;
  background: #79A70A;
  background: linear-gradient(#9BC90D 0%, #79A70A 100%);
  box-shadow: 0 3px 10px -5px rgba(0, 0, 0, 1);
  position: absolute;
  top: 19px; left: -21px;
}
.ribbon span::before {
  content: "";
  position: absolute; left: 0px; top: 100%;
  z-index: -1;
  border-left: 3px solid #79A70A;
  border-right: 3px solid transparent;
  border-bottom: 3px solid transparent;
  border-top: 3px solid #79A70A;
}
.ribbon span::after {
  content: "";
  position: absolute; right: 0px; top: 100%;
  z-index: -1;
  border-left: 3px solid transparent;
  border-right: 3px solid #79A70A;
  border-bottom: 3px solid transparent;
  border-top: 3px solid #79A70A;
}
<div class="picture">

    <div class="ribbon ribbon-top-left">
      <span>TEXT</span>
    </div>

    <img src="http://i.imgur.com/5lWqOGT.png" />
    
</div>

This always worked because the image below the ribbon markup always had fixed dimensions, so when the image is resized the ribbon is resized together and both get smaller (or bigger) equally.

However, I'm now redesigning a UI in which I don't want things to shrink or grow without much control, so I'm using Bootsrap for the Grid and vh / vw units for some other properties like width, height, border...

And this is the problem with this ribbon code. In this new approach, when resizing the viewport, the image (for this example) hardly changes its dimensions, but the ribbon, because was created in pixels, gets too small (or too big).

Here, let's take the same code above, but now let's add a height: 60vh to the img:

body {
  margin: 10%
}

img {
  border-radius: 0.5vw;
  height: 60vh;
}

.picture {
  position: relative;
}

.ribbon {
  position: absolute;
  left: -5px; top: -5px;
  z-index: 1;
  overflow: hidden;
  width: 75px; height: 75px;
  text-align: right;
}
.ribbon span {
  font-size: 10px;
  font-weight: bold;
  color: #FFF;
  text-transform: uppercase;
  text-align: center;
  line-height: 20px;
  transform: rotate(-45deg);
  -webkit-transform: rotate(-45deg);
  width: 100px;
  display: block;
  background: #79A70A;
  background: linear-gradient(#9BC90D 0%, #79A70A 100%);
  box-shadow: 0 3px 10px -5px rgba(0, 0, 0, 1);
  position: absolute;
  top: 19px; left: -21px;
}
.ribbon span::before {
  content: "";
  position: absolute; left: 0px; top: 100%;
  z-index: -1;
  border-left: 3px solid #79A70A;
  border-right: 3px solid transparent;
  border-bottom: 3px solid transparent;
  border-top: 3px solid #79A70A;
}
.ribbon span::after {
  content: "";
  position: absolute; right: 0px; top: 100%;
  z-index: -1;
  border-left: 3px solid transparent;
  border-right: 3px solid #79A70A;
  border-bottom: 3px solid transparent;
  border-top: 3px solid #79A70A;
}
<div class="picture">

    <div class="ribbon ribbon-top-left">
      <span>TEXT</span>
    </div>

    <img src="http://i.imgur.com/5lWqOGT.png" />
    
</div>

Now resize the viewport and you'll see.

I tried to replace all units used in the original code with vw / vh but, apparently, this is not enough - or I'm doing something wrong >.<

So, is it possible to create these ribbons and make them fluid, responsive, fixed... (I'm not sure the right term here, sorry) and make them proportional to the viewport when resizing like the image?

I've tested several other codes but in summary all of them have a box with fixed dimensions for the ribbon to work, just like this one. The closest I've found was this pen in which I was able to remove its box dimensions but when adding the image with the vh unit, the same thing happened.

  • 3
    Very much interested as well – user5613506 Jul 18 '17 at 15:40
  • Would this be a similar question https://stackoverflow.com/questions/43924916/css-grid-position-absolute-an-element-in-a-css-grid-item-impossible/43926006#43926006 pen that goes along https://codepen.io/gc-nomade/details/mmLboy/ – G-Cyrillus Jul 18 '17 at 15:46
  • I can't tell for sure. I forked this pen and tried to add the `` inside the grid with the ribbon but the ribbon sticked in the grid itself, not in the image. Could you help me? –  Jul 18 '17 at 15:58

2 Answers2

3

If you scale the width and the position with CSS vh (since you're already scaling your image height with vh), you can adjust it responsively:

width: 40vh;
top: 9.3vh;
left: -7.7vh;

You could do same with the font-size and line-height. See the Fiddle below.

Demo: JSFiddle

trevorp
  • 1,161
  • 1
  • 14
  • 19
  • @user5613506 Does [this answer](https://jsfiddle.net/te9kakfy/1/) meet your requirements, too? – trevorp Jul 18 '17 at 16:50
  • Yours is too much large but simply reducing the `width` is not enough to make it more to the top and left. Is there a ratio between the properties or just by trial and error? –  Jul 18 '17 at 18:19
  • Yep, it's a little bit of trial and error. I've made it smaller: [Fiddle](https://jsfiddle.net/te9kakfy/2/) – trevorp Jul 18 '17 at 18:28
  • _Alternatively:_ If you want one that scales based on the width of the image, you can do it this way: [Fiddle](https://jsfiddle.net/te9kakfy/) – trevorp Jul 18 '17 at 18:30
  • One last thing, kind of offtopic, is there an article or something about when to use `vh` or `vw`? I may be wrong but I'm using `vh` for Y-axis or vertical things (height, padding-top...) and `vw` for X-axis or horizontal things (width, padding-left...). But working over your example, I've found very hard to position perfectly, for example, `left` using `vw`. –  Jul 18 '17 at 18:35
  • [This article](https://www.elegantthemes.com/blog/divi-resources/better-mobile-website-design-how-to-use-vw-vh-and-rem-to-create-fluid-divi-pages) might help understand why/when to use them. It's just another way responsively scale things that would otherwise be hard to scale uniformly (padding, fonts, etc). – trevorp Jul 18 '17 at 18:42
  • Well, with the information I've got here (and from other sources) I've adjusted the code, separating what colorizes it and what controls its positioning to have all four sides with just a class change. I'll let the link for a CodePen [here](https://codepen.io/package-001/full/weLwxJ/) if anyone is interested. Too bad that, unfortunately, at this point the positioning is not "plug n' play", different images seems to require different values (by very little, though) and I've noticed differences between Chrome and Firefox as well. But, it's something ¯\\_(ツ)_/¯ –  Jul 18 '17 at 20:56
1

This is as close as I could get. I used the CSS calc() function to multiply vh to get fractions. It looks okay at least in Safari.

body {
  margin: 10%
}

img {
  border-radius: 0.5vw;
  height: 60vh;
}

.picture {
  position: relative;
}

.ribbon {
  position: absolute;
  left: calc(100vh * -0.01);
  top: calc(100vh * -0.01);
  z-index: 1;
  width: calc(100vh * 0.15); 
  height: calc(100vh * 0.15);
  overflow: hidden;
}
.ribbon span {
  font-size: calc(100vh * 0.025);
  font-weight: bold;
  color: #FFF;
  text-transform: uppercase;
  text-align: center;
  line-height: calc(100vh * 0.05);
  transform: rotate(-45deg) translate(-25%, -30%);
  -webkit-transform: rotate(-45deg) translate(-25%, -30%);
  width: calc(100vh * 0.15);
  display: block;
  background: #79A70A;
  background: linear-gradient(#9BC90D 0%, #79A70A 100%);
  box-shadow: 0 calc(100vh * 0.0075) calc(100vh * 0.0125) 0 rgba(0,0,0,0.4);
  position: absolute;
}

.ribbon span::before {
  content: "";
  position: absolute; left: 0px; top: 100%;
  z-index: -1;
  border-left: calc(100vh * 0.01) solid #79A70A;
  border-right: calc(100vh * 0.01) solid transparent;
  border-bottom: calc(100vh * 0.01) solid transparent;
  border-top: calc(100vh * 0.01) solid #79A70A;
}
.ribbon span::after {
  content: "";
  position: absolute; right: 0px; top: 100%;
  z-index: -1;
  border-left: calc(100vh * 0.01) solid transparent;
  border-right: calc(100vh * 0.01) solid #79A70A;
  border-bottom: calc(100vh * 0.01) solid transparent;
  border-top: calc(100vh * 0.01) solid #79A70A;
}
<div class="picture">

    <div class="ribbon ribbon-top-left">
      <span>TEXT</span>
    </div>

    <img src="http://i.imgur.com/5lWqOGT.png">
    
</div>
Nicholas
  • 115
  • 6