I have a table that contains contenteditable=true cells.
I wish to insert a button into those cells but the problem is that I can backspace those buttons away and I don't want that too happen.
Here is what I am doing:
<table><tr>
<td contenteditable=true>Text Here
<button>Don't delete me!</button>
</td>
I don't want to create two spans inside the cell, one editable and one not, because I cant figure out how to make it fill the entire cell.
You can separate the button into another <td>.
td {border: dashed 1px red}
<table>
<tr>
<td contenteditable="true">Text Here
<td contenteditable="false"><button>Don't delete me!</button></td>
<td contenteditable="true">After button Text Delete me
</td>
</tr>
</table>
Don't nest any elements inside an element with contenteditable unless you don't care about them being deleted. Nest a contenteditable element within the <td> or put the <button> outside of <td> and use position:relative or transform:translate over the <td>. This Snippet demonstrates three ways.
The second and third examples are fragile and can break easily, the first example is the best and most simplest.
SNIPPET
.ghost {
position: relative;
right: 150%;
top: 14px;
}
.extended {
position: relative;
right: 12%;
vertical-align: top;
}
.bg {
position: relative;
right: 170%;
z-index: 0;
width: 100%;
height: 100%;
}
.up {
position: relative;
right: 170%;
z-index: 1;
}
button {
display: block;
}
td {
min-width: 210px;
}
<table>
<tr>
<td>
<label contenteditable=true>Example 1</label>
<button>Don't delete me!</button>
</td>
<td class='extended' contenteditable=true>
Example 2
</td>
<td>
<button class='ghost'>Don't delete me!</button>
</td>
<td>
<div class='bg' contenteditable=true>Example 3</div>
<button class='up'>Don't delete me!</button>
</td>
</tr>
</table>
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;
}
http://jsfiddle.net/HnnHf/1/
Trying to understand what I do wrong. Plain table, I want input boxes to fill cells evenly. On first row you see 2 inputs and second row has one input spanned across cells.
Their right sides don't match. Why? When I run inspector it shows additional pixels?
Part of my HTML:
<div style="width: 1000px; margin-left: auto; margin-right: auto; padding-left: 20px; padding-top: 10px;">
<table>
<tr>
<td style="width: 80px;"><label>From </label></td>
<td style="width: 120px;">
<input type="text" class="fill-space" />
</td>
<td style="width: 80px;"><label>To </label></td>
<td style="width: 120px;">
<input type="text" class="fill-space" />
</td>
<td style="width: 80px;"><label>Sort by </label></td>
<td></td>
</tr>
<tr>
<td colspan="6"> </td>
</tr>
<tr>
<td></td>
<td colspan="3">
<input type="text" class="search" />
</td>
<td></td>
<td>
Refresh button
</td>
</tr>
</table>
</div>
Style:
td label {
width: 100%;
color: #F1F1F1;
text-align: right;
vertical-align: central;
}
input.fill-space {
width: 100%;
}
input.search {
width: 100%;
background-image: url("/images/Search.png");
background-position: right center;
background-repeat: no-repeat;
}
</style>
My live site misalignment:
Also, why do I get this another border inside input if I set background?
Working fiddle: http://jsfiddle.net/ghUEw/
Default padding and margins for table elements differ in different browsers.
So you'd better use a CSS reset on table elements.
table * {
margin: 0;
padding: 0;
}
Then, comes the border-collapse property. It determines whether the table borders are collapsed into a single border or rendered individually, let's say for neighboring table cells. You need to set it as following to make them collapsed since you have different number of cells per table row.
table {
border-collapse: collapse;
}
Then, you need to set the borders of the inputs in your table if you want them look the same.
table input {
border: 1px solid #aaa;
}
If you don't want any borders to appear, replace it with border: none;
Then, in your CSS, for the labels to appear the way you want, you can apply float:right; (also corrected vertical-align: middle;)
td label {
width: 100%;
color: #F1F1F1;
text-align: right;
vertical-align: middle;
float:right;
}
I'm using a <table> to layout a standard HTML contact form. Let's not discuss the merits of using a table given that HTML should not be about presentation but structure (which is why I believe it's justified anyway).
Nonetheless, here is the markup and CSS I'm using (as-generated by ASP.NET MVC):
<table class="fieldTable">
<tbody>
<tr>
<th><label for="Name">Your name</label></th>
<td><input id="Name" name="Name" type="text" value="" /></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<th><label for="EmailAddress">Your e-mail address</label></th>
<td><input id="EmailAddress" name="EmailAddress" type="text" value="" /></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<th><label for="MessageBody">Message</label></th>
<td><textarea cols="30" id="MessageBody" name="MessageBody" rows="6"></textarea></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td><button type="submit"><span>Send Message</span></button></td>
</tr>
</tbody>
</table>
And my CSS:
.fieldTable th {
text-align: right;
font-weight: normal;
vertical-align: top;
padding: 0.25em;
padding-right: 0.5em; }
.fieldTable input,
.fieldTable textarea,
.fieldTable button {
width: 100%; }
input, textarea, button {
border: 1px solid #999;
padding: 0.5em;
border-radius: 5px;
-webkit-box-shadow: 0px 0px 7px 3px #c4c4c4;
box-shadow: 0px 0px 7px 3px #c4c4c4; }
button { background: #DDD; position: relative; }
button:hover { background: #FFF; }
button:active span { position: relative; top: 2px; left: 2px; }
tr { outline: 1px solid blue; }
td { outline: 1px solid red; }
However it seems to render like this:
Why isn't the <button> element filling the cell horizontally?
I think you might be looking for box-sizing, it is what determines if the margin/padding get added or excluded when calculating the width/height.
box-sizing: border-box;
That should allow you to set a percentage width/height and it will fill without spilling over.
EDIT: It is on button by default (if you inspect the element you will see the browser already adds it). It can be added to your textareas and input fields to get them to match up with your buttons.
If you look at your screen shots. The input fields are going outside of the TDs and the button seems to be the only one really behaving.
David I took a look at your html and created a jsFiddle based on it. I then modified your css to use the box-sizing property you're looking for. Although its applied to other objects on the DOM you might want to extract it into its own class for only the textareas.
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>