html/css: Draw borders through a table cell - html

I have a very simple table:
<table>
<tr>
<td>col1</td><td>col2</td><td>col3</td>
</tr>
<tr>
<td colspan=2>Mybigcell</td><td>col3</td>
</tr>
</table>
What I want to achieve is to draw a border around the first column, that means around col1 and the left part of Mybigcell. The border thus has to run through the middle of Mybigcell.
Is it possible?

You can use absolute positioned pseudo-elements to achieve this.
Just use the CSS below and add class="border" to some cell. Its column will obtain a border.
Basically, it works like this:
We will insert some absolute positioned pseudo-elements with top: 0 and bottom: 0. Their containing block will be the table rectangle (position: relative), so the pseudo-elements will grow to cover all the column.
These pseudo-elements will be inserted at the beginning of the cells (::before). Assuming left aligning inside the cells, they will be aligned at the desired position.
Note they can't be aligned using left: 0 (and we can't use ::after with right: 0 neither) because the containing block is the table, not the cell. If the containing block was the cell this would be more reliable, but the borders wouldn't fill all the column.
Therefore, if a cell has a border class, a pseudo-element will be inserted in that cell (the left border), and in the following one (the right border).
But if the cell with the border class was the last one in the row, it would have no right border, because there is no following cell.
To fix that, I use the :last-child pseudo-class to detect this case, and then I insert an ::after pseudo-element with left: 100%. As mentioned above, it will be aligned relatively to the table instead of the cell. But assuming there is no missing cell in the row, that won't matter because the right edge of the cell and the right edge of the table will coincide.
Finally, I do some small adjustments using negative margins, to make it pixel perfect.
table {
position: relative; /* Containing block for the borders */
border-collapse: collapse;
}
td {
padding: 1px;
padding-left: 2px; /* Increase by borderWidth */
}
.border:before, .border + :before, .border:last-child:after {
content: ''; /* Enable the pseudo-element */
position: absolute; /* Take it out of flow */
top: 0; /* From the top of the table... */
bottom: 0; /* ...to the bottom of the table */
border-left: 1px solid;/* This produces the border */
margin-left: -2px; /* Same as td's paddingLeft, in negative */
}
.border:last-child:after {
left: 100%; /* Place it at the right */
margin-left: 0; /* Remove the margin set previously */
}
<table> <tr> <td class="border">col1</td> <td>col2</td> <td>col3</td> </tr>
<tr> <td colspan=3>Mybigbigcell</td> </tr> </table><hr />
<table> <tr> <td>col1</td> <td class="border">col2</td> <td>col3</td> </tr>
<tr> <td colspan=3>Mybigbigcell</td> </tr> </table><hr />
<table> <tr> <td>col1</td> <td>col2</td> <td class="border">col3</td> </tr>
<tr> <td colspan=3>Mybigbigcell</td> </tr> </table><hr />
<table> <tr> <td>col1</td> <td>col2</td> <td class="border">col3</td> <td>col4</td> </tr>
<tr> <td colspan=4>Mybigbigbigcell</td> </tr> </table>
If you want to customize the width of the borders or the paddings, see the SCSS:
/* Parameters */
$borderWidth: 1px;
$padding: 1px;
/* Code */
$sum: $borderWidth + $padding;
table {
position: relative;
border-collapse: collapse;
}
td {
padding: $padding;
padding-left: $sum;
}
.border:before, .border + :before, .border:last-child:after {
content: '';
position: absolute;
top: 0;
bottom: 0;
border-left: $borderWidth solid;
margin-left: - $sum;
}
.border:last-child:after {
left: 100%;
margin-left: 0;
}

Related

HTMLTable: Empty link element should take up whole cell space

I am using a (bootstrap) table where I put a link inside one of the cells, where it might happen, that the actual link text is empty, thus not showing the link element (or better to say the user can't click it). Now the goal is, that the link element should take up the whole cell space regardless of whether there is some text in the link or not.
<table class="table table-bordered table-striped">
<tr>
<td><a ...>Text that might be empty</a></td>
...
I have tried setting the display property of the a-tag to inline-table which worked for the most browsers except IE. Is there a nice, clean and crossbrowser compatible way to achieve this?
Give the anchor a display: block. It then will take the full width of its parent.
I've made you this demo. By clicking the button, you'll see how it works.
Note, that the anchor should at least have 'something' in it.
$('button').click(function() {
$('a').toggleClass('block');
});
td {
border: 1px solid red;
}
tr, td {
height: 100%;
}
a {
background: blue;
}
a.block {
display: block;
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td> </td>
<td>Text<br />text</td>
</tr>
<tr>
<td>Text text</td>
<td>Text text</td>
</tr>
</table>
<button>Toggle block</button>
Set min-width for the column
<td style="min-width:50px"><a ...>Text that might be empty</a></td>
This will work with/without text.
.hasLink{
position: relative;
height: 38px;
}
.hasLink a{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
font-size: 0px; //if you don't want to show any text
padding: 8px 0 0 5px;
}
<tr>
<td class="hasLink"></td>
<td></td>
</tr>

Perfectly align text to the top of table cell

How can i perfectly align text to the top of a table cell? By perfectly, I mean that the top of the letters touch the border of the table cell.
An additional difficulty in my case is that I need to use a large line height (approximately double the font height). As a result, there's is a considerable space between the top of the letters and the cell border because the difference between the font height and the line height is distributed equally to both the top and bottom of the text (so called half-leading).
I've setup a JSFiddle.
<table>
<tbody>
<tr>
<td> </td>
<td>NOT PROPERLY ALIGNED TO THE TOP</td>
</tr>
</tbody>
</table>
table {
width: 100%;
table-layout: fixed;
border-collapse: collapse;
padding: 0;
margin: 0;
}
td {
height: 200px;
vertical-align: top;
font-size: 18px;
line-height: 40px;
border: solid 1px black;
background-color: #ddd;
}
How about wrapping necessary text in some spans and adding negative position/margin, like
span {
position: relative;
top: -12px;
}
Fiddle
But for a good readability, you'd rather don't need to remove space at top (imho)
Look, the text at left side looks better.
If you changed your html to:
<table>
<tbody>
<tr>
<td> </td>
<td><span>NOT PROPERLY ALIGNED TO THE TOP</span></td>
</tr>
</tbody>
</table>
adding <span> tags
Then you can go:
td span {
margin-top: -15px;
}
Hope this helps
Demo
The issue is because of the line-height
You can change the line-height of the first line by using the selector :first-line like
td:first-line {
line-height: 10px;
}
I have a solution but it goes with JS, not pure CSS only.
HTML (added the 'span' tag inside 'td'):
<table>
<tbody>
<tr>
<td> </td>
<td>
<span id="myText">PROPERLY ALIGNED TO THE TOP</span>
</td>
</tr>
</tbody>
</table>
JS:
$(document).ready(function(){
var span = $("#myText");
var lineHeight = parseInt(span.css("line-height"));
var fontSize = parseInt(span.css("font-size"));
var shift = (lineHeight-fontSize)/2;
var shiftPx = "-"+shift+"px";
//alert(lineHeight);
//alert(fontSize);
span.css({
"position":"relative",
"top":shiftPx
});
});
Full jsfiddle: http://jsfiddle.net/jondinham/p8g1cx6b/

Negative margin on table row

How do I give a <tr> a negative margin to move it up? I'm trying to move .small-item-block
<tr>
<td class="item-name">Caprese</td>
<td class="item-description">Fresh mozzarella, tomato, fresh basil and balsamic vinegar on a bed of spinach.</td>
<td>$4.00</td>
<td>$20.00</td>
</tr>
<tr class="small-item-block" >
<td class="item-name"></td>
<td class="item-addition-name">Add Bacon</td>
<td class="item-addition-price">$1.00</td>
<td class="item-addition-price">$3.00</td>
</tr>
CSS
tr.small-item-block {
margin-top: -10px;
border-spacing: -10px;
}
Here is the JS Fiddle.
You can't move a tr, but you can set the td's to position: relative, and then set a negative top property, like:
tr.small-item-block td {
position: relative;
top: -10px;
}
Here's your fiddle updated: http://jsfiddle.net/L4gLM/2/
You can't really move a row any higher than the row above it, so I think your best bet would be to remove margin/padding from the <td>s inside that <tr>. Example:
tr.small-item-block td {
margin-top: 0;
padding-top: 0;
}

Overflow:hidden not working in Firefox?

I have a table with rounded corner, and I've put an overflow: hidden CSS command on it so that the corners of the individual cells don't protrude out. It works fine on Chrome, but not on Firefox. Can someone tell me what's wrong?
<style>
table {
border-spacing: 0px;
border: 1px solid #222;
border-radius:8px;-moz-border-radius:8px;-webkit-border-radius:8px;
overflow: hidden;
}
th {
height: 30px;
color: #fff;
background: #222;
text-align: left;
}
tr:nth-child(even) {
background: #245876;
color: #fff;
border: none;
height: 25px;
}
tr:nth-child(odd) {
height: 23px;
}
.pos {
width: 50px;
}
.name {
width: 175px;
}
</style>
<table>
<thead>
<tr>
<th class="pos"></th>
<th class="name">Name</th>
<th class="amount">Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td class="pos">1</td>
<td class="name">Bob</td>
<td class="amount">1324353</td>
</tr>
<tr>
<td class="pos">2</td>
<td class="name">John</td>
<td class="amount">10611</td>
</tr>
<tr>
<td class="pos">3</td>
<td class="name">Bill</td>
<td class="amount">3270</td>
</tr>
<tr>
<td class="pos">4</td>
<td class="name">Brian</td>
<td class="amount">1950</td>
</tr>
<tr>
<td class="pos">5</td>
<td class="name">Dan</td>
<td class="amount">1760</td>
</tr>
</tbody>
</table>
The spec does not require the behavior you are looking for: "The ‘border-radius’ properties do apply to ‘table’ and ‘inline-table’ elements. When ‘border-collapse’ is ‘collapse’, the UA may apply the border-radius properties to ‘table’ and ‘inline-table’ elements, but is not required to." (http://dev.w3.org/csswg/css-backgrounds/#border-radius-tables)
It is possible it simply will not work in Firefox. If that's the case, you could apply border-radius to the header cells (:first-child and :last-child in the header row), but it doesn't always line up properly. A bit of a PITA, I know.
thead tr th:first-child { border-radius:8px 0 0 0; }
thead tr th:last-child { border-radius:0 8px 0 0; }
This might help. How to make CSS3 rounded corners hide overflow in Chrome/Opera
Add where you want:
-moz-overflow: hidden;
I like Pete Scott's answer. But depending on your design, you can create the radius effect on a table by wrapping the table itself in a containing element that has the radius left and right, overflow hidden. Then, position relative the table, and -*px to create the required visual effect. But without seeing the desired end result, I am unable to provide an example.
It's possible to change the effect of overflow on the table element with the following trick: change the display of the table, e.g., to inline-block (this value preserves the shrink-fit width of the table and shouldn't break the layout assuming the table is surrounded by block elements). The resulting rendering will be equivalent as if the table has the div wrapper with border-radius and overflow, which renders in Firefox without problems. Here is the JSbin example.

Linethrough/strikethrough a whole HTML table row

After some research, I couldn't find an answer to this question. There was this but it didn't really answer my question. I would like to "strikethrough" a complete HTML table row in CSS, not just the text in it. Is it at all possible? From the example that I linked, it seems tr styling doesn't even work in Firefox. (And anyway, text-decoration only applies on text afaik)
Oh yes, yes it is!
CSS:
table {
border-collapse: collapse;
}
td {
position: relative;
padding: 5px 10px;
}
tr.strikeout td:before {
content: " ";
position: absolute;
top: 50%;
left: 0;
border-bottom: 1px solid #111;
width: 100%;
}
HTML:
<table>
<tr>
<td>Stuff</td>
<td>Stuff</td>
<td>Stuff</td>
</tr>
<tr class="strikeout">
<td>Stuff</td>
<td>Stuff</td>
<td>Stuff</td>
</tr>
<tr>
<td>Stuff</td>
<td>Stuff</td>
<td>Stuff</td>
</tr>
</table>
http://codepen.io/nericksx/pen/CKjbe
My answer (below) said that it is not possible. I was wrong, as pointed out by #NicoleMorganErickson. Please see her answer (and upvote it!) for how to do it. In short, you use :before pseudo-class to create an element that draws a border across the middle of the cell, above the content:
table { border-collapse:collapse } /* Ensure no space between cells */
tr.strikeout td { position:relative } /* Setup a new coordinate system */
tr.strikeout td:before { /* Create a new element that */
content: " "; /* …has no text content */
position: absolute; /* …is absolutely positioned */
left: 0; top: 50%; width: 100%; /* …with the top across the middle */
border-bottom: 1px solid #000; /* …and with a border on the top */
}
(original answer)
No, it is not possible using only CSS and your semantic table markup. As #JMCCreative suggests, it is possible visually using any number of ways to position a line over your row.
I would instead suggest using a combination of color, background-color, font-style:italic and/or text-decoration:line-through to make the entire row obviously different. (I'd personally strongly 'fade out' the text to a color much closer to the background than normal text and make it italic.)
tr {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NkYGCQBAAAIwAbDJgTxgAAAABJRU5ErkJggg==');
background-repeat: repeat-x;
background-position: 50% 50%;
}
I used http://www.patternify.com/ to generate the 1x1 image url.
Edit
In a recent Bootstrap 4.3 ServiceNow Angular.js project, I found myself having to make some changes, and instead used the following CSS, similar to the experience of Revoman:
tr.strikeout td.strike-able:before {
content: " ";
position: absolute;
display: inline-block;
padding: 12px 10px;
left: 0;
border-bottom: 2px solid #d9534f;
width: 100%;
}
Original Post
I like Nicole Morgan Erickson's answer, but it might cause side effects if your implement his solution verbatim. I've add some small tweaks to keep this kosher, below... so that we're not globally modifying every table or every td with this CSS.
I also wanted a button on the row to strike out the row, but I didn't want to strike out the column with the button, for visibility sake. I just wanted to strike out the rest of the row. For this, I made it so that every column that wants to be capable of showing the strike out must declare such by also being marked with a class. In this iteration, you'd need to mark the table as strike-able, and also mark each td as strike-able; but you gain safety by not side effecting any non-strike-able tables, and you gain control of which columns to strike out.
CSS:
table.strike-able {
border-collapse: collapse;
}
table.strike-able tr td {
position: relative;
padding: 3px 2px;
}
table.strike-able tr th {
position: relative;
padding: 3px 2px;
}
table.strike-able tr.strikeout td.strike-able:before {
content: " ";
position: absolute;
top: 50%;
left: 0;
border-bottom: 2px solid #d9534f;
width: 100%;
}
Usage:
<table class="strike-able" id="Medications" data-item-count="#Model.Medications.Count">
<tr>
<th>
Some Column
</th>
<th>
Command Column
</th>
</tr>
<tr class="strikeout">
<td class="strike-able"></td>
<td>Button that Toggles Striking Goes Here (active)</td>
</tr>
<tr>
<td class="strike-able"></td>
<td>Button that Toggles Striking Goes Here</td>
</tr>
</table>
Lastly, since I'm using this with Bootstrap, and treating the deletions as a dangerous thing to do, I've formatted the colors a little to match my use.
EDIT: As pointed out by #Mathieu M-Gosselin in the comments, this actually puts the line behind the text. That said, if your line is the same color as your text or you are using a small-ish font, this still works pretty well.
For what it's worth, here's a pretty effective way to do it in pure CSS without using pseudo elements. You can change the thickness of the strikethrough line by adjusting the background-size.
table {
border-collapse: collapse;
}
td {
width: 100px
}
.strikethrough {
background: repeating-linear-gradient(
180deg,
red 0%,
red 100%
);
background-size: 100% 2px;
background-position: center;
background-repeat: no-repeat;
}
<table>
<tr>
<td>Foo</td>
<td>Bar</td>
<td>Baz</td>
</tr>
<tr class="strikethrough">
<td>Foo Strike</td>
<td>Bar Strike</td>
<td>Baz Strike</td>
</tr>
</table>
#NicoleMorganErickson, I like your answer, but I could not get the strikeout to affect only the applied row. Also, I needed it to be applied multiple rows so I modified your solution down into a single class.
CSS:
tr.strikeout td:before {
content: " ";
position: absolute;
display: inline-block;
padding: 5px 10px;
left: 0;
border-bottom: 1px solid #111;
width: 100%;
}
http://codepen.io/anon/pen/AaFpu
Yes you can. In the first cell of the row you create a div containing a HR. Float the div to the left and specify its width as a % of its containing element, in this case the table cell. It'll stretch as wide as you want across the table cells in that row, even beyond the width of the table if you want.
This works for me:
<style>
.strikeThrough {
height:3px;
color:#ff0000;
background-color:#ff0000;
}
.strikeThroughDiv {
float:left;
width:920%;
position:relative;
top:18px;
border:none;
}
</style>
<table width="900" border="1" cellspacing="0" cellpadding="4">
<tr valign="bottom">
<td>
<div class="strikeThroughDiv"><hr class="strikeThrough"/></div>
One
</td>
<td>
<label for="one"></label>
<input type="text" name="one" id="one" />
</td>
<td>
<label for="list"></label>
<select name="list" id="list">
<option value="One">1</option>
<option value="Two">2</option>
<option value="Three" selected>3</option>
</select>
</td>
<td>
Four
</td>
<td>
Five
</td>
</tr>
</table>
To control the width of your line you have to specify the width of the table cell containing the HR. For styling HR elements they say you shouldn't make it less than 3px in height.
Here's a very simple way that worked for me:
<table>
<tbody style="text-decoration: line-through">
-- Various table body stuff
</tbody> </table>
Not sure but it seems there were other answers mentioning simple and straightforward pure CSS solution...
#Ben Slade's answer is the closest of all, but still...
Just use text-decoration: line-through in your CSS! Add corresponding class and then use <tr class="strikethrough">!
.strikethrough {
text-decoration: line-through;
}
table,
th,
td {
border: 1px solid black;
}
<table>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<tr class="strikethrough">
<td>Centro comercial Moctezuma</td>
<td>Francisco Chang</td>
<td>Mexico</td>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
</tr>
</table>