2

I am working on a system (maybe you guessed it from the snippet, it's confluence) and try to style tables.

Important I have no chance to modify the table-html output, I can only add some CSS styles. The tables can occur in every combination on a page and are added by users.

This is the structure and possible table comibnations - this is only an example - there are other combinations.

.confluenceTable {
 border-collapse: collapse;
}

.confluenceTh, .confluenceTd {
 padding: 6px 8px;
 border: 1px solid #888a85;
 border-right: none;
 border-bottom: none;
}

table.confluenceTable tr:first-child .confluenceTh, 
table.confluenceTable tr:first-child .confluenceTd {
 border-top: none;
}

.confluenceTh:first-child, .confluenceTd:first-child {
 border-left: none;
}



table.confluenceTable thead tr:first-child .confluenceTh {
  border-bottom: 2px solid #CC0018;
}

table.confluenceTable tr .confluenceTh + :not(.confluenceTh) {
  border-left: 2px solid #CC0018; 
}
<h2>First</h2>
<p>table without headers</p>
<table class="confluenceTable">
  <tbody>
    <tr>
      <td class="confluenceTd">1.1</td>
      <td class="confluenceTd">2.1</td>
      <td class="confluenceTd">3.1</td>
    </tr>
    <tr>
      <td class="confluenceTd">1.2</td>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <td class="confluenceTd">1.3</td>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>
<h2>Second</h2>
<p>table with column header</p>
<table class="confluenceTable">
  <thead>
    <tr>
      <th class="confluenceTh">1.1</th>
      <th class="confluenceTh">2.1</th>
      <th class="confluenceTh">3.1</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="confluenceTd">1.2</td>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <td class="confluenceTd">1.3</td>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>
<h2>Third</h2>
<p>table with row header</p>
<table class="confluenceTable">
  <tbody>
    <tr>
      <th class="confluenceTh">1.1</th>
      <td class="confluenceTd">2.1</td>
      <td class="confluenceTd">3.1</td>
    </tr>
    <tr>
      <th class="confluenceTh">1.2</th>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <th class="confluenceTh">1.3</th>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>
<h2>Fourth</h2>
<p>table with row and column header</p>
<table class="confluenceTable">
  <thead>
    <tr>
      <!-- This element should also have a border right -->
      <th class="confluenceTh">1.1</th>
      <th class="confluenceTh">2.1</th>
      <th class="confluenceTh">3.1</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th class="confluenceTh">1.2</th>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <th class="confluenceTh">1.3</th>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>

The Problem is the Fourth table - I found no way to add a border-right to 1.1, which is column and row header. Does anyone see a pure CSS solution?

In a future step, there might also be headers in the middle of a table...

ppasler
  • 3,164
  • 4
  • 25
  • 42
  • It is impossible to solve this using pure CSS. You want to detect if there is a `th` in a `tr` in the table body and depending on that, change the style of a column in the table head. However, CSS only supports selectors that go down the DOM tree, never up (to parent elements), which is what you would need. You need a class on the table (head), which you could add via JavaScript. – Just a student Mar 04 '17 at 11:59
  • @Justastudent thanks, maybe this was the reason I didn't find a solution - because there is none. You may post this as an answer and I'll accept it. – ppasler Mar 04 '17 at 12:12
  • Just did. Sorry for the late reply, I wanted to take the time to write up a decent answer for you :-) – Just a student Mar 06 '17 at 07:58
  • 1
    @Justastudent no problem, your comment was an answer already, so I didn't invest further time to find a CSS solution. I also used JS now, but it's frustrating for such a "simple" thing. – ppasler Mar 06 '17 at 11:56

3 Answers3

2

Make use of nth-of-type pseudo selector as below to select 4th table and add border to right-side of th first-child.

The :nth-of-type(an+b) CSS pseudo-class matches an element that has an+b-1 siblings with the same element name before it in the document tree, for a given positive or zero value for n, and has a parent element.

table.confluenceTable:nth-of-type(4) > thead > tr > th:first-child{
  border-right:2px solid #CC0018;
}

.confluenceTable {
 border-collapse: collapse;
}

.confluenceTh, .confluenceTd {
 padding: 6px 8px;
 border: 1px solid #888a85;
 border-right: none;
 border-bottom: none;
}

table.confluenceTable tr:first-child .confluenceTh, 
table.confluenceTable tr:first-child .confluenceTd {
 border-top: none;
}

.confluenceTh:first-child, .confluenceTd:first-child {
 border-left: none;
}



table.confluenceTable thead tr:first-child .confluenceTh {
  border-bottom: 2px solid #CC0018;
}

table.confluenceTable tr .confluenceTh + :not(.confluenceTh) {
  border-left: 2px solid #CC0018; 
}
table.confluenceTable:nth-of-type(4) > thead > tr > th:first-child{
  border-right:2px solid #CC0018; /*Add this*/
}
<h2>First</h2>
<p>table without headers</p>
<table class="confluenceTable">
  <tbody>
    <tr>
      <td class="confluenceTd">1.1</td>
      <td class="confluenceTd">2.1</td>
      <td class="confluenceTd">3.1</td>
    </tr>
    <tr>
      <td class="confluenceTd">1.2</td>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <td class="confluenceTd">1.3</td>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>
<h2>Second</h2>
<p>table with column header</p>
<table class="confluenceTable">
  <thead>
    <tr>
      <th class="confluenceTh">1.1</th>
      <th class="confluenceTh">2.1</th>
      <th class="confluenceTh">3.1</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="confluenceTd">1.2</td>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <td class="confluenceTd">1.3</td>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>
<h2>Third</h2>
<p>table with row header</p>
<table class="confluenceTable">
  <tbody>
    <tr>
      <th class="confluenceTh">1.1</th>
      <td class="confluenceTd">2.1</td>
      <td class="confluenceTd">3.1</td>
    </tr>
    <tr>
      <th class="confluenceTh">1.2</th>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <th class="confluenceTh">1.3</th>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>
<h2>Fourth</h2>
<p>table with row and column header</p>
<table class="confluenceTable">
  <thead>
    <tr>
      <!-- This element should also have a border right -->
      <th class="confluenceTh">1.1</th>
      <th class="confluenceTh">2.1</th>
      <th class="confluenceTh">3.1</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th class="confluenceTh">1.2</th>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <th class="confluenceTh">1.3</th>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>
frnt
  • 7,861
  • 2
  • 16
  • 23
  • Thanks, this works for this particular example. The problem is, I am looking for a gerneric solution. – ppasler Mar 04 '17 at 12:11
  • @ppasler Okay, so your code contains many tables, so using nth-of-type you can select particular table and style. – frnt Mar 04 '17 at 12:19
  • This is for a wiki system so the user input what they want. text, images, whatever and tables. There can be many tables which can have several row and column headers. – ppasler Mar 04 '17 at 12:27
  • Okay @ppasler then you need to come-up some unique idea, what I mean is at-present there are just four tables, first doesn't got any style whereas 2nd,3rd and 4th as, so could assign different class to them and apply same style every-time when this type of table layout are found. – frnt Mar 04 '17 at 12:34
  • That is exactly my problem, I can't modify the html of a table, although I can change content of a table (it's a wysiwyg editor). I really appreciate your effort, but it's not exactly what I need. – ppasler Mar 04 '17 at 12:50
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/137229/discussion-between-frnt-and-ppasler). – frnt Mar 04 '17 at 15:08
1

Try this)

body > .confluenceTable:nth-child(12) thead tr:first-child th:first-child   {
    border-right: 2px solid #CC0018; 
}

Live demo - https://jsfiddle.net/grinmax_/wxfL4ocg/

grinmax
  • 1,719
  • 1
  • 8
  • 13
  • Thanks, this works if I only have these fixed tables, but I need a generic solution for user input. – ppasler Mar 04 '17 at 11:51
1

Your problem, more generally
You have the following structure in your HTML.

element.A1
  element.A2
element.B1
  element.B2

Now, you want to style A2 depending on some properties B2 has. For example, if B2 is present, if B2 is a specific type of element (like a div or span), if it has a certain attribute ([data-foo="bar"]), et cetera.

Solving using CSS
Unfortunately, it is currently not possible to do this using a pure CSS solution. This is because all selectors in CSS go from an element to any descendant of that element, but never the other way around. For example, a b selects all elements of type b that are a descendant of a. With a > b, only children of a type elements are considered. There is however no way to go the other way.

Solving using JS + CSS
For now, you can solve your problem by using a certain class and applying that class using JavaScript. Something along the lines of the following.

.A1.special .A2 {
    /* special styling on A2 */
}
var b2s = document.querySelectorAll('.B2'), i;
for (i = 0; i < b2s.length; ++i) {
    if (isSpecial(b2s[i])) {
        b2s[i].parentNode.previousSibling.classList.add('special');
    }
}

References: querySelectorAll, parentNode, previousSibling, classList.

The isSpecial function would check for whatever properties you would want to check for. In particular, I implemented your specific question in the following snippet.

// detect special case and add class for CSS styling
var firstRows = document.querySelectorAll('.confluenceTable tbody > tr:first-child'), i;
for (i = 0; i < firstRows.length; ++i) {
  if (firstRows[i].querySelector('th') !== null) {
    firstRows[i].parentNode.parentNode.classList.add('special');
  }
}
.confluenceTable {
 border-collapse: collapse;
}

.confluenceTh, .confluenceTd {
 padding: 6px 8px;
 border: 1px solid #888a85;
 border-right: none;
 border-bottom: none;
}

table.confluenceTable tr:first-child .confluenceTh, 
table.confluenceTable tr:first-child .confluenceTd {
 border-top: none;
}

.confluenceTh:first-child, .confluenceTd:first-child {
 border-left: none;
}

table.confluenceTable thead tr:first-child .confluenceTh {
  border-bottom: 2px solid #CC0018;
}

table.confluenceTable tr .confluenceTh + :not(.confluenceTh) {
  border-left: 2px solid #CC0018; 
}

/* add styling for the exceptional case */
table.confluenceTable.special > thead > tr > th:first-child{
  border-right:2px solid #CC0018;
}
<h2>First</h2>
<p>table without headers</p>
<table class="confluenceTable">
  <tbody>
    <tr>
      <td class="confluenceTd">1.1</td>
      <td class="confluenceTd">2.1</td>
      <td class="confluenceTd">3.1</td>
    </tr>
    <tr>
      <td class="confluenceTd">1.2</td>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <td class="confluenceTd">1.3</td>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>
<h2>Second</h2>
<p>table with column header</p>
<table class="confluenceTable">
  <thead>
    <tr>
      <th class="confluenceTh">1.1</th>
      <th class="confluenceTh">2.1</th>
      <th class="confluenceTh">3.1</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="confluenceTd">1.2</td>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <td class="confluenceTd">1.3</td>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>
<h2>Third</h2>
<p>table with row header</p>
<table class="confluenceTable">
  <tbody>
    <tr>
      <th class="confluenceTh">1.1</th>
      <td class="confluenceTd">2.1</td>
      <td class="confluenceTd">3.1</td>
    </tr>
    <tr>
      <th class="confluenceTh">1.2</th>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <th class="confluenceTh">1.3</th>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>
<h2>Fourth</h2>
<p>table with row and column header</p>
<table class="confluenceTable">
  <thead>
    <tr>
      <!-- This element should also have a border right -->
      <th class="confluenceTh">1.1</th>
      <th class="confluenceTh">2.1</th>
      <th class="confluenceTh">3.1</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th class="confluenceTh">1.2</th>
      <td class="confluenceTd">2.2</td>
      <td class="confluenceTd">3.2</td>
    </tr>
    <tr>
      <th class="confluenceTh">1.3</th>
      <td class="confluenceTd">2.3</td>
      <td class="confluenceTd">3.3</td>
    </tr>
  </tbody>
</table>
Community
  • 1
  • 1
Just a student
  • 9,016
  • 2
  • 36
  • 59