KienHT
KienHT

Reputation: 1346

Pseudo elements position absolute doesn't respect its relative parent element in Safari

I'm trying to create a spacer/separator between rows in a table (please note it's not between EVERY row, but only between some specific rows). The approach I'm taking right now is to create an empty tr (to add some space), and add a pseudo element tr:after to it (to draw a grey horizontal line sits in the center of that empty space). Everything works perfectly fine until I try it on Safari.

In Chrome, Firefox and Edge (expected): https://ibb.co/wNSykPQ

In Safari: https://ibb.co/0tsLkym

This is my markup:

<table class="context-menu">
  <tr>
    <td>Cut</td>
    <td>Ctrl+X</td>
  </tr>
  <tr class="spacer"></tr>
  <tr class="disabled">
    <td>Paste</td>
    <td>Ctrl+Z</td>
  </tr>
  <tr>
    <td>Copy</td>
    <td>Ctrl+C</td>
  </tr>
</table>

This is the styles for tr.spacer:

table.context-menu tr.spacer {
  position: relative;
  height: 8px;
}
table.context-menu tr.spacer:after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto 0;
  height: 1px;
  width: 100%;
  background-color: var(--item-disabled);
}

Full demo here: https://jsfiddle.net/tfkox4yc/10/

I have explicitly set tr.spacer position to relative, so the pseudo element tr.spacer:after should respect tr.spacer position. I add top 0, bottom 0 and margin-top margin-bottom auto to make it vertically center in tr.spacer. However in Safari, it doesn't seem to be the case, it seems like the pseudo element is relative to the table, not its parent. Is there anything I'm missing here?

Upvotes: 1

Views: 599

Answers (2)

Johannes
Johannes

Reputation: 67778

Your tr.spacer is empty, i.e. it does not contain any (td) cells, which is invalid HTML. Every row has to have the same amount of cells (or there have to be according colspan attributes)

so your HTML should look like this:

<table class="context-menu">
  <tr>
    <td>Cut</td>
    <td>Ctrl+X</td>
  </tr>
  <tr class="spacer"><td></td><td></td></tr>
   <tr>
    <td>Copy</td>
    <td>Ctrl+C</td>
  </tr>
  <tr class="disabled">
    <td>Paste</td>
    <td>Ctrl+V</td>
  </tr>

</table>

I tried it with your jsfiddle in Safari, it works as desired.

Upvotes: 1

HomeSlice
HomeSlice

Reputation: 622

If I understand you correctly, you want to create a context menu and place a spacer only between specific rows. I have had mixed results trying to style table rows, try adding [td] elements to the spacer row and style those instead. But also, instead of using a [table], perhaps consider using a [menu].

Table:

    table.context-menu {
        --item-active: #316ac4;
      --item-disabled: #ABA89A;
      --table-padding: 2px;
      list-style: none;
      position: absolute;
      left: 0;
      padding: 2px;
      margin: 0;
      color: #000;
      background-color: #FFF;
      border: 1px var(--item-disabled) solid;
      border-collapse: separate;
      border-spacing: 0px;
      min-width: 10em;
    }

    table.context-menu tr.spacer {
  position: relative;
  height: 8px;
}
table.context-menu tr.spacer td:after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  margin: auto 0;
  height: 1px;
  width: 100%;
  background-color: var(--item-disabled);
}
table.context-menu > tbody > tr > td {
  white-space: nowrap;
  padding: 4px 1em;
}
table.context-menu > tbody > tr.disabled > td {
  color: var(--item-disabled);
}
table.context-menu > tbody > tr:not(.disabled):hover > td {
  cursor: default;
  background-color: var(--item-active);
  color: #fff;
}
table.context-menu > tbody > tr > td:first-of-type {
  width: 100%;
}
table.context-menu > tbody > tr > td.children {
  position: absolute;
  padding: 0;
}
table.context-menu > tbody > tr:not(.disabled) > td.children {
  position: relative;
}
table.context-menu > tbody > tr:not(.disabled) > td.children:after {
  content: "";
  position: absolute;
  right: 5px;
  top: 0;
  bottom: 0;
  margin: auto 0;
  width: 0;
  height: 0;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-left: 5px solid #000;
}
table.context-menu > tbody > tr:not(.disabled):hover > td.children:after {
  border-left-color: #FFF;
}
table.context-menu > tbody > tr > td.children > table.context-menu {
  display: none;
}
table.context-menu > tbody > tr:not(.disabled):hover > td.children > table.context-menu {
  top: 0;
  display: table;
}
<table class="context-menu">
      <tr>
        <td>Cut</td>
        <td>Ctrl+X</td>
      </tr>
      <tr class="spacer">
          <td></td>
          <td></td>
      </tr>
       <tr>
        <td>Copy</td>
        <td>Ctrl+C</td>
      </tr>
      <tr class="disabled">
        <td>Paste</td>
        <td>Ctrl+V</td>
      </tr>
    </table>

Menu:

menu.context-menu {
        --item-active: #316ac4;
        --item-disabled: #ABA89A;
        --table-padding: 2px;
        list-style: none;
        box-sizing: border-box;
        padding: 2px;
        position: absolute;
        left: 0;
        width: 100%;
        border: 1px solid var(--item-disabled);
    }

    .grid {
        display: grid;
        border-width: 1px 0 0 0;
        grid-template-columns: repeat(2, 1fr);
        justify-content: space-beteen;
    }

    .grid > span {
        padding: 5px;
        white-space: nowrap;
    }

    .grid > span:last-child {
        text-align: right;
    }

    .grid:not(.disabled):hover {
        background-color: var(--item-active);
        color: #fff;
    }

    .grid.disabled {
        color: var(--item-disabled);
    }

    .spacer {
        height: 1px;
        border: solid var(--item-disabled);
        border-width: 0 0 1px 0;
        margin: 2px;
    }
<menu class="context-menu">
      <li class="grid">
        <span>Cut</span>
        <span>Ctrl+X</span>
      </li>
      <li class="spacer"></li>
      <li class="grid">
        <span>Copy</span>
        <span>Ctrl+C</span>
      </li>
      <li class="grid disabled">
        <span>Paste</span>
        <span>Ctrl+V</span>
      </li>
    </menu>

Upvotes: 2

Related Questions