CSS Grid, position absolute an element in a css grid item: IMPOSSIBLE
Asked Answered
G

4

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;
  }
}
Grams answered 11/5, 2017 at 20:24 Comment(2)
you need to put position: relative; on grid-item and then you can use absolute position on .ribbon-wrapperPavlish
Please include all relevant code in a minimal reproducible example in the question itself, not only on a third-party website.Eulaliaeulaliah
H
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>
Hobbism answered 11/5, 2017 at 21:38 Comment(8)
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?Grams
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?Grams
@JohnSam it should with a bit of tunning , codepen.io/gc-nomade/pen/mmLboy you can lay 2 backgrounds on top of each other with different value for background-clipHobbism
@JohnSam 315deg is equal to 360deg/0 minus 45 . no difference in fact :)Hobbism
Dear @GCyrillus, can you see this? #44025790Grams
@JohnSam i won't be any help here, i do not have a mac to check on safari :(Hobbism
Also with iPad/iPhone, it's the same.Grams
@JohnSam idem, got none of them . i took a look, your css seems to meet what is required to make it work....Hobbism
P
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/

Pavlish answered 11/5, 2017 at 20:33 Comment(1)
Please include all relevant code in a minimal reproducible example in the answer itself, not only on a third-party website.Eulaliaeulaliah
C
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
}
Cubiculum answered 11/5, 2017 at 20:45 Comment(3)
what your comment's typo . css comments are /* comment */Hobbism
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 firstHobbism
@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 thisCubiculum
H
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

Hassan answered 11/5, 2017 at 20:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.