Search code examples
htmlcssposition

absolute div inside fieldset with legend


Why does the .discount-edg container not align to the top right corner of my fieldset? If I remove the <legend>, it works. And why do Chrome and Firefox display different?

body {
  margin: 100px;
}

fieldset {
  border: 1px solid #E67E22;
  width: 300px;
  height: 200px;
  padding: .625rem;
  position: relative;
}
fieldset legend {
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  margin: 0px 10px;
  padding: 0px 10px;
}
fieldset .discount-edg {
  text-align: center;
  color: #FFF;
  position: absolute;
  top: 0;
  right: 0;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 0 50px 50px 0;
  border-color: transparent #ff0000 transparent transparent;
}
fieldset .discount-edg .value {
  position: absolute;
  top: 10px;
  left: 16px;
  white-space: nowrap;
  font-weight: 700;
  transform: rotate(45deg);
}
<fieldset>
  <legend>Testlegend with long text that wraps</legend>
  <div class="discount-edg"><div class="value">- 50%</div></div>
</fieldset>


Solution

  • The discount edge does align with the top of the fieldset, it's just that the top border of a fieldset will always run through the middle of a legend.

    From w3.org:

    A fieldset element’s rendered legend, if any, is expected to be rendered over the block-start border edge of the fieldset element as a block box (overriding any explicit display value). In the absence of an explicit inline size, the box should shrink-wrap. If the legend element in question has an align attribute, and its value is an ASCII case-insensitive match for one of the strings in the first column of the following table, then the legend is expected to be rendered aligned in the inline direction over the border edge in the position given in the corresponding cell on the same row in the second column.

    The difference between firefox and chrome is caused by a bug in the way webkit handles collapsed margins for fieldsets

    I would change to use divs as using fieldsets for anything other than group form controls is semantically incorrect anyway.

    body {
      margin: 100px;
    }
    
    .fieldset {
      border: 1px solid #E67E22;
      width: 300px;
      height: 200px;
      padding: .625rem;
      position: relative;
    }
    .fieldset .legend {
      font-size: 14px;
      font-weight: 700;
      text-transform: uppercase;
      margin: 0px 60px 0 10px;
      padding: 0px 10px;
      position:absolute;
      background:white;
      top:0;
      transform: translateY(-50%);
    }
    .fieldset .discount-edg {
      text-align: center;
      color: #FFF;
      position: absolute;
      top: 0;
      right: 0;
      width: 0;
      height: 0;
      border-style: solid;
      border-width: 0 50px 50px 0;
      border-color: transparent #ff0000 transparent transparent;
    }
    .fieldset .discount-edg .value {
      position: absolute;
      top: 10px;
      left: 16px;
      white-space: nowrap;
      font-weight: 700;
      transform: rotate(45deg);
    }
    <div class="fieldset">
      <div class="legend">Test legend with long text that wraps</div>
      <div class="discount-edg"><div class="value">- 50%</div></div>
    </div><br><br>
    <div class="fieldset">
      <div class="legend">One line</div>
      <div class="discount-edg"><div class="value">- 50%</div></div>
    </div>