4

I have this situation: https://jsfiddle.net/rozkvsdh/5/

A CSS Grid, simply, but in some items, I need to put a ribbon or another div.

It's impossible!

How can I do?

 grid-item {
  background-color: lightgreen;
  display: flex;
  justify-content: center;
  align-items: center;
}

.ribbon-wrapper {
  width: 85px; // the length should be not in px I think!
  height: 88px; // the length should be not in px I think!
  overflow: hidden;
  //position: absolute; it doesn't work!
  position: relative;
  top: -3px;
  left: -3px;
  .ribbon {
    font: bold 15px sans-serif;
    color: #333;
    text-align: center;
    -webkit-transform: rotate(-45deg);
    -moz-transform: rotate(-45deg);
    -ms-transform: rotate(-45deg);
    -o-transform: rotate(-45deg);
    position: relative;
    padding: 7px 0;
    top: 15px;
    left: -30px;
    width: 120px;
    background-color: #ebb134;
    color: #fff;
  }
}
Ivan
  • 34,531
  • 8
  • 55
  • 100

4 Answers4

3

you could use a pseudo and a data attribute :

HTML5 is designed with extensibility in mind for data that should be associated with a particular element but need not have any defined meaning. data-* attributes allow us to store extra information on standard, semantic HTML elements without other hacks such as non-standard attributes, extra properties on DOM

overflow can be used and background-clip can help to mimic ribbon standing a bit outside

The background-clip CSS property specifies whether an element's background, either the color or image, extends underneath its border.

vmin or vmax units could be used to set font-size to resize the ribbon via em on padding and coordonates.

The viewport-percentage lengths are relative to the size of the initial containing block. When the height or width of the initial containing block is changed, they are scaled accordingly.

eventually, shadow can be added and linear-gradient can help to draw slanted shadow's parts.

Demo:

body {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  grid-auto-rows: 1fr;
  grid-gap: 2px;
  height: 100vh;
  padding: 5px;
  margin: 0;
  box-sizing: border-box;
}

grid-item {
  background-color: lightgreen;
  background-clip: content-box;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  overflow: hidden;
  padding: 3px;
}

grid-item[data-class="new"]:before {
  content: attr(data-class);
  position: absolute;
  font-size: 2vmax; /* update font-size */
  top: 0.4em;
  left: -1.3em;
  padding: 0em 1.5em;
  transform: rotate(315deg);
  background-color:gold;
  /* eventually add some shadow effects */
  background-image: 
  linear-gradient(135deg, black 0.9em, transparent 1.15em), 
  linear-gradient(-135deg, black 0.9em, transparent 1.15em);
  box-shadow: 0 0 3px;
}
<grid-item>see</grid-item>
<grid-item>full</grid-item>
<grid-item>page</grid-item>
<grid-item>then</grid-item>
<grid-item data-class="new">RESIZE</grid-item>
<grid-item>window</grid-item>
<grid-item>to</grid-item>
<grid-item>see</grid-item>
<grid-item>ribbon</grid-item>
<grid-item data-class="new">font&size</grid-item>
<grid-item>updates</grid-item>
<grid-item>F</grid-item>
<grid-item data-class="new">PRO</grid-item>
<grid-item>B</grid-item>
<grid-item>C</grid-item>
<grid-item>D</grid-item>
<grid-item>E</grid-item>
<grid-item>F</grid-item>
<grid-item>A</grid-item>
<grid-item>B</grid-item>
G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
  • Thanks @GCyrillus, beautiful solution! Thanks very much! It's amazing! :D Why `rotate(315deg)` and not `rotate(-45deg)`? A particular reason? And why if I have just one big grid-item and padding "width" is not enough? –  May 12 '17 at 00:01
  • And just another: If I have a `border: 1px solid black` on grid-item how can I use that ribbon over the border? `background-clip` is not good for that, right? –  May 12 '17 at 00:04
  • @JohnSam it should with a bit of tunning , https://codepen.io/gc-nomade/pen/mmLboy you can lay 2 backgrounds on top of each other with different value for background-clip – G-Cyrillus May 12 '17 at 10:02
  • @JohnSam 315deg is equal to 360deg/0 minus 45 . no difference in fact :) – G-Cyrillus May 12 '17 at 19:35
  • Dear @GCyrillus, can you see this? http://stackoverflow.com/questions/44025290/flexbox-strange-behaviour-with-cssgrid –  May 17 '17 at 12:49
  • @JohnSam i won't be any help here, i do not have a mac to check on safari :( – G-Cyrillus May 17 '17 at 12:53
  • Also with iPad/iPhone, it's the same. –  May 17 '17 at 12:57
  • @JohnSam idem, got none of them . i took a look, your css seems to meet what is required to make it work.... – G-Cyrillus May 17 '17 at 13:12
2

you need to put position: relative; on grid-item and then you can use absolute position on .ribbon-wrapper.

grid-item {
  background-color: lightgreen;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}

.ribbon-wrapper {
  width: 85px; // the length should be not in px I think!
  height: 88px; // the length should be not in px I think!
  overflow: hidden;
  position: absolute;
  top: -3px;
  left: -3px;
  .ribbon {
    font: bold 15px sans-serif;
    color: #333;
    text-align: center;
    -webkit-transform: rotate(-45deg);
    -moz-transform:    rotate(-45deg);
    -ms-transform:     rotate(-45deg);
    -o-transform:      rotate(-45deg);
    position: relative;
    padding: 7px 0;
    top: 15px;
    left: -30px;
    width: 120px;
    background-color: #ebb134;
    color: #fff;
  }
}

https://jsfiddle.net/thesouthstar86/rozkvsdh/6/

Brian Glaz
  • 15,468
  • 4
  • 37
  • 55
1

You can do it and also works for resize but it's a bit messy.

The spacer divs are there so you have the height. You need one on each side because you want PRO to be centered. We sacrifice 1px on each side to make this work and now ribbon-wrapper can be absolute

https://jsfiddle.net/rozkvsdh/9/

HTML

<grid-item>

    <div class="ribbon-wrapper"><div class="ribbon">NEW</div></div>    
    <div class="spacer"></div>
    <div>PRO</div>
    <div class="spacer"></div>

</grid-item>

CSS

// this is new
.spacer {
  height: 88px;
  width: 1px;
}

grid-item {
  background-color: lightgreen;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative; // added
}
.ribbon-wrapper {
  width: 85px; // the length should be not in px I think!
  height: 88px; // the length should be not in px I think!
  overflow: hidden;
  position: absolute;
  top: 0; // edited
  left: 0; // edited
}
Huangism
  • 16,278
  • 7
  • 48
  • 74
  • 1
    what your comment's typo . css comments are `/* comment */` – G-Cyrillus May 11 '17 at 21:06
  • I meant you should have advised him about it instead copy/paste it's way to comment ;) I did upvote your answer anyway cause of relative/absolute behavior that was missing at first – G-Cyrillus May 12 '17 at 14:24
  • 1
    @GCyrillus there is nothing to advise him, the comments are correct. As you can see in the question the OP has `.ribbon-wrapper { ... .ribbon { ... } }`. This isn't how CSS is written because you can't nest them like that, let's just say OP is using LESS and comments like `// ...` are valid. I formatted the question a little so it is easier to see this – Huangism May 12 '17 at 18:11
0

The ribbon won't align left because it's an in-flow child of a flex container with justify-content: center. So both the ribbon and the content are centered side-by-side.

You can override that setting with margin-right: auto, which will left-align the ribbon, but it will also right-align the content.

You can insert an invisible spacer item to create equal balance in the container, keeping the content centered. But that's a bit involved and may be unnecessary.

Stick with CSS positioning properties. This will position the ribbon. Re-sizing it is another matter:

grid-item {
    background-color: lightgreen;
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative; /* establish nearest positioned ancestor for abspos containment */
}

.ribbon-wrapper {
    overflow: hidden;
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
}

.ribbon-wrapper .ribbon {
    font: bold 15px sans-serif;
    color: #333;
    text-align: center;
    transform: rotate(-45deg);
    position: relative;
    padding: 7px 0;
    top: 15px;
    left: -30px;
    width: 15vw;
    background-color: #ebb134;
    color: #fff;
}

revised fiddle

Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701