How to make empty contenteditable spans keep their height - html

I have an editable span element that will be initially empty. Its height varies when it's empty and when its not, and can't figure out how to make give it the correct height.
<b>Foo:</b> <span contenteditable>Bar</span>-<span contenteditable></span>
span[contenteditable]
{
display: inline-block;
min-width: 2ch;
height: 1em;
padding: 0 .2em;
outline: 1px solid #text-subtle-color;
}

As noted by #temani-afif and #facundo-corradini, this issue seems to be an inssue only in FireFox. With a couple more searches with that in the query I found a simple fix that seems to work, and also not mess anything up in the other browsers:
*[contenteditable]:empty:before
{
content: "\feff"; /* ZERO WIDTH NO-BREAK SPACE */
}
Note: If I drop the :empty selector, which was not part of the linked answer nor the answer of #facundo-corradini here, things looks off again. Their extra does also not seem to make a difference.

You can do it with the Flexbox:
.flex-container {
display: inline-flex; /* takes only the content's width */
/*align-items: stretch; by default / takes care of the equal height among all flex-items (children) */
}
.flex-container > * {
margin: 0 5px; /* just for demonstration */
}
span[contenteditable] {
/*display: inline-block;*/
min-width: 2ch;
/*height: 1em;*/
/*padding: 0 .2em;*/
/*outline: 1px solid #text-subtle-color;*/
border: 1px solid; /* also this */
}
<div class="flex-container">
<b>Foo:</b> <span contenteditable>Bar</span>-<span contenteditable></span>
</div>
<div class="flex-container">
<b>Foo:</b> <span contenteditable>Bar</span>-<span contenteditable>123</span>
</div>

It's an issue with empty content editable specifically on Firefox.
A workaround is to set a pseudo-element containing a zero width no-break space "character" as follows:
span[contenteditable]
{
display: inline-block;
min-width: 2ch;
height: 1em;
padding: 0 .2em;
outline: 1px solid grey;
box-sizing:border-box;
content="";
}
span[contenteditable]:before {
content: "\feff ";
}
<b>Foo:</b> <span contenteditable>Bar</span>-<span contenteditable placeholder=""> </span>

Related

Why does fractional pixel padding give the parent element additional width?

This is best explained through my JSFiddle. I'm using Chrome.
I have an inline-block container element. Inside of it are inline elements (spans).
<div id="container">
<span class="star">★</span><span class="star">★</span>
</div>
When I give the star class padding of 5px, the border of the container renders as expected, at the edge of the last element.
When I change the padding to 5.5, or one of many other decimal values, the container appears to have additional width on one side (the more inner elements, the more profound this effect is).
Actually, I suspect that the container doesn't have extra width, but that the inner elements have too little width. Notice how the blue box displayed by Chrome's element inspector is narrower that in should be in the first example.
When the element is inline:
when the element is inline-block:
What's going on here?
Ok, let's try to get to a reasonable conclusion.
Using fractional pixels is not wrong, but it doesn't work quite exactly as we would expect, since most browsers will round up the fractional number to an integer one.
I wish I could give you an official reference regarding this matter, but I can't. It is not a standard, it's just the way some browsers decided to render it. (if someone can find a reference, please feel free to update the answer)
Now, with that information in mind:
It's just a matter of math:
(This measures are calculated in Google Chrome)
Without padding, your star character has a width of 13.33px. And you are adding a surrounding padding of 5.5px. So:
FIRST STAR SECOND STAR
-------------------- -------------------
5.5 | 13.33 | 5.5 5.5 | 13.33 | 5.5
-------------------- -------------------
Summing up: 5.5 + 13.33 + 5.5 + 5.5 + 13.33 + 5.5 = 48.66
So the parent element is told by the browser that it's inner contents sum up to 48.66px, but based on what we have considered, it will render as 49px.
If that's true, then a 49px element should be exactly the same size of your example, as it is:
#container {
display: inline-block;
border: dashed 1px red;
}
#compare {
border: dashed 1px blue;
width: 49px;
text-align: center;
margin-bottom: 10px;
}
.star {
padding: 5.5px;
background-color: lightgray;
}
<div id="compare">49px</div>
<div id="container">
<span class="star">★</span><span class="star">★</span>
</div>
Conclusion:
You may ask, why isn't the inner content also rounded up to a total of 49px?
Apparently, the browser will round up or down depending of the fractional, so 13.33px will round to 13px on the inner elements, causing it to render smaller than its parent.
Fractional pixels are allowed, you can refer to this answer: Can a CSS pixel be a fraction?
However, it depends on the browser how it interprets it. If you open your fiddle in IE11 the width is correct (funny IE11 being 'better' at something).
A quick test on safari show us that they are fit. Look:
The best way to fight with this is adding the border to the star. Take a look here:
#container {
display: inline-block;
border: dashed 1px red;
}
#container2 {
display: inline-block;
}
.star {
/* This creates extra width. */
padding: 5.5px;
background-color: lightgray;
}
.star2 {
/* This is fine. */
padding: 5px;
background-color: lightgray;
}
.star3 {
/* This is fine. */
padding: 5.5px;
border-top: dashed 1px red;
border-bottom: dashed 1px red;
background-color: lightgray;
}
.star3:first-child {
border-left: dashed 1px red;
}
.star3:last-child {
border-right: dashed 1px red;
}
<div id="container">
<span class="star">★</span><span class="star">★</span>
</div>
<div id="container">
<span class="star2">★</span><span class="star2">★</span>
</div>
<div id="container2">
<span class="star3">★</span><span class="star3">★</span><span class="star3">★</span>
</div>
#container {
display: inline-block;
border: dashed 1px red;
}
.star {
/* This creates extra width. */
/* padding: 4.48px 6.72px; */
/* This is fine. */
/* padding: 5px; */
/* This creates extra width. */
padding: 5.5px;
display: inline-block;
background-color: lightgray;
}
<div id="container">
<span class="star">★</span><span class="star">★</span>
</div>
#container {
display: inline-block;
border: dashed 1px red;
}
.star {
/* This creates extra width. */
/* padding: 4.48px 6.72px; */
/* This is fine. */
/* padding: 5px; */
/* This creates extra width. */
padding: 5.5px;
display: inline-block;
background-color: lightgray;
}

Why line-height in Firefox and Chrome is different?

I created multi-line-padded text based on Matthew Pennell's solution (codepen by CSS Tricks). In Chrome all looks fine, but in Firefox height of span elements bigger than height of their ancestor. If I adjust vertical padding for Firefox, in Chrome will be same problem, and vice versa.
Why it happens? What the real technical reasons of this problem?
HTML Code:
<div class="padded-multiline">
<h1>
<strong>How do I add padding to subsequent lines of an inline text element?</strong>
</h1>
</div>
CSS Code:
:root {
font-family: Arial, sans-serif;
font-size: 20px;
}
.padded-multiline {
line-height: 1.3;
padding: 2px 0;
border-left: 20px solid #c0c;
width: 400px;
margin: 20px auto;
}
.padded-multiline h1 {
background-color: #c0c;
padding: 4px 0;
color: #fff;
display: inline;
margin: 0;
}
.padded-multiline h1 strong {
position: relative;
left: -10px;
}
Setting a line-height: 1; on strong will fix the problem also read my comment.
Chrome and Firefox seems to use different text layout system.
In Chrome it will floor the line-height attribute and Firefox seems to use the correct one.
To achieve the same effect for title, just use only the outline.
H1 does not need strong.
.padded-multiline {
line-height: 1.3;
padding: 2px 0;
width: 400px;
margin: 20px auto;
}
.padded-multiline h1 {
background-color: #c0c;
padding:1px;
color: #fff;
display: inline;
outline: 10px solid #c0c;
margin: 0;
font-size:16px;
}
<div class="padded-multiline">
<h1>How do I add padding to subsequent lines of an inline text element?</h1>
</div>
Here is codepen: http://codepen.io/anon/pen/vgRvjM
If you need exactly visual (that means less purple space from top and bottom, you can use for example border from after and before):
.padded-multiline:before{
content:'';
display:block;
border:5px solid #fff;
position:relative;
left:-10px;
top:-3px;
}
.padded-multiline:after{
content:'';
display:block;
border:5px solid #fff;
position:relative;
left:-10px;
bottom:-3px;
}
Codepen for this solution: http://codepen.io/anon/pen/QdmzxK
Unfortunately, there isn't a full and clean crossbrowser workaround. Because different UAs render text different, height of each textline may be taller a bit (or vice verca). So, I create a solution based on SCSS calculations of required box' sizes, and hide artefacts via overflow property.
Here is my solution, if you meet the same problem: http://codepen.io/ifiri/pen/ygEeeL
HTML:
<p class="multiline-text">
<span class="multiline-text__wrapper multiline-text__wrapper--outer">
<span class="multiline-text__wrapper multiline-text__wrapper--left">
<span class="multiline-text__wrapper multiline-text__wrapper--right">Multiline Padded text, which looks great on all browsers. No artefacts, no hacks, all clear and flexy, all alignment support. Change SCSS variables for see how it works.</span>
</span>
</span>
</p>
SCSS:
/*
Variables
*/
$base-line-height: 1.75;
$base-font-size: 1.25em;
$multiline-padding-base: ($base-line-height / 2) * 1em;
$multiline-padding-horizontal: $multiline-padding-base;
$multiline-padding-vertical: $multiline-padding-base - (1em / 2);
$multiline-bg-color: #a5555a;
$multiline-font-color: #fff;
/*
= Snippet Styles
This code is required
*/
.multiline-text {
color: $multiline-font-color;
padding: 0px $multiline-padding-horizontal;
// hide line-height artefacts
overflow: hidden;
position: relative;
}
.multiline-text__wrapper {
background-color: $multiline-bg-color;
padding: $multiline-padding-vertical 0px;
}
.multiline-text__wrapper--outer {
// Inner padding between text lines
line-height: $base-line-height;
}
.multiline-text__wrapper--left {
position: relative;
left: -($multiline-padding-horizontal);
}
.multiline-text__wrapper--right {
position: relative;
right: -($multiline-padding-horizontal / 2);
}

Make text invisible in printed version of the document - avoid color correction

I have a simple "fill the gaps" excercise in html. There are gaps, looking like this:
Earth closest star is _ _ _ _.
The gaps are not supposed to be fillable on the computer - the document is supposed to be printed with the gaps enpty. But they have a content so, when howered, answers may be checked.
I use border-bottom property to make the gaps. There is a text filled in the gaps but it is white, so the user only can see it on hover.
The CSS:
span.gap {
color: white;
border-bottom: 1px solid black;
}
span.gap:hover {
color: gray;
}
The HTML:
Stephen Hawking is famous for his research of <span class="gap">black holes</span>.
Stackoverflow only helps you if you ask <span class="gap">simple questions</span>.
Browser seems to fix the color from white to black, so the gap content is visible in the printed document. How should I hide the text then?
I cannot use the visibility property, because the border must be visible.
Of all of the image replacement techniques, there are a few that will work without adding extra elements. All of them will require setting a width on the span if you want it to appear inline.
http://jsfiddle.net/TZD84/
span.gap {
display: inline-block;
width: 8em;
white-space: pre;
overflow: hidden;
border-bottom: 1px solid black;
text-indent: 110%;
}
span.gap:hover {
color: gray;
text-indent: 0;
}
If you need to support older browsers, there's always the negative text-indent method
http://jsfiddle.net/TZD84/1/
span.gap {
display: inline-block;
width: 8em;
overflow: hidden;
border-bottom: 1px solid black;
text-indent: -10em;
}
span.gap:hover {
color: gray;
text-indent: 0;
}
You can use CSS media types to handle different display/media situations. I.e add something like this to your CSS:
#media print { .gap { /* add your styles */ }}
Also, in combination with this you could add a separate span that would display only for print. Like:
HTML:
Stackoverflow only helps you if you ask
<span class="gap">simple questions</span>
<span class="print-gap"></span>.
CSS:
span.gap, span.print-gap {
color: white;
border-bottom: 1px solid black;
}
span.gap:hover {
color: gray;
}
#media screen {
span.print-gap { display: none; }
}
#media print {
span.gap { display: none; }
span.print-gap { display: inline-block; width: 100px; }
}

How would you design the HTML markup for this

I want to make something like a horizontal line with a text in the middle of it. It should look like this (text image follows):
------------------------------------------ TEXT --------------------------------------------
the line should be dotted and the text in the middle should separate the line in half.
I came up with the idea of using a table with 3 elements with percentage values in width attribute but maybe there is a better solution.
I hope it's clear. Thanks for ideas
<div id="line"><span>TEXT</span></div>
And CSS:
#line{
border-bottom: 1px black dotted;
overflow:visible;
height:9px;
text-align:center;
margin: 5px 0 10px 0;
}
#line span{
background-color: white;
text-align:center;
padding: 0 5px;
}
See Example on JSFiddle
I would use CSS, and two containers:
Demo: http://jsfiddle.net/LRSuJ/
HTML:
<div class="something">
<div class="content">Text</div>
</div>
CSS:
.something {
border-bottom: dotted 1px #000;/* Border style */
height: 10px; /* Adjusted height */
margin-bottom: 10px; /* Proper offset for next element */
line-height: 20px; /* Actual text height */
text-align: center; /* Center text */
}
.content {
background-color: #FFF; /* Hide previous dots */
display: inline; /* Inline element */
padding: 0 10px; /* Customisable left/right whitespace */
}
You could use a fieldset and legend:
<fieldset>
<legend>TEXT</legend>
</fieldset>
fieldset
{
border-top:solid 1px black;
}
fieldset legend
{
text-align:center;
}
http://jsfiddle.net/2amBc/
I would do it like this:
HTML
<fieldset>
<legend>Text with dotted line</legend>
</fieldset>
CSS
fieldset {
border: 0;
border-top: 1px dotted gray;
}
legend {
text-align: center;
}
jsFiddle demo: http://jsfiddle.net/XZcRB/

Apply CSS style to <div>

My problem is with the below html
<div class="editor-container">
<div class="editor-row curFocus">
<div class="editor-label">
<label for="FirstName">First Name</label>
</div>
<div class="editor-field">
<input class="text-box single-line valid" id="FirstName"
name="FirstName" type="text" value="Nancy" maxlength="20">
</div>
</div>
</div>
When the user selects the input field, I add class "curFocus" to the outer div via some javascript to highlight both label and the input field.
My css is -
.editor-container {
border: thin solid #444444;
display: table; width: 100%;
}
.editor-row {
width: 100%; display: table-row;
}
.editor-label {
padding-left: .4em; width: 40%;
}
.editor-label, .editor-field {
padding-right: .4em; padding-bottom: .2em; padding-top: .2em;
display: table-cell;
}
.curFocus {
border: 2px solid #05365b;
background-color: #d3e5f2;
margin: 3px; padding: 3px;
}
My problem is that while using debuggers in Chrome 12 and IE9, they both show the border settings being applied to the outer div. But, when viewing the form, neither browser display's the specified border. All other css settings work correctly. I also tried changing definition of ".curFocus" to ".curFocus div". But this applied the style to each of the nested div's also, but did display borders on all of the divs.
While I'm not a CSS expert, it is not obvious why this shouldn't work.
Edit
Here is jsfiddle link - http://jsfiddle.net/photo_tom/KmsF5/1/. While testing this it does work correctly in IE9 if in IE7 compatibly mode. Otherwise, it does not display correctly.
Sorry about not including link, still getting use to fact that jsfiddle even exists.
Well, I can tell you what's causing it, but I can't tell you why. Elements with display: table-row; can't have a border applied to them. You can apply the border to the table-cell children of the .curFocus element, but not the table-row itself.
Again, no idea why this silly rule exists, but you can fix your problem with some CSS:
.curFocus {
background-color: #d3e5f2;
margin: 3px; padding: 3px;
}
.curFocus>div {
border: 2px solid #05365b;
border-width: 2px 0px; /* top and bottom border for all the table-row's immediate children (table-cells) */
}
.curFocus>div:first-child {
border-width: 2px 0px 2px 2px; /* left border for the leftmost table-cell */
}
.curFocus>div:last-child {
border-width: 2px 2px 2px 0px; /* right border for the rightmost table-cell */
}
See http://jsfiddle.net/d772N/
I think your problem is your display type on the .editor-row. display: table-row; Remove that and the problem will go away. Plus I don't think that all browsers support display: table-row; very well.
You might need a higher CSS specificity, as it is ambiguous which CSS styles will apply with the current definitions.
Try div.curFocus rather than .curFocus div for the class definition to apply the style to the div with that class name rather than its div children.