No line break between text and SVG - css

I have a short text that is followed by an SVG in a limited-width container.
The expected behaviour is that the text breaks if it's longer than the container width BUT I would like it NOT to break right between the text and the svg:
Current result:
Expected result:
Adding a <nobr> or a <span>tag in the middle of the text (before blue) and closing it after the SVG is not an option as the text comes from an external database and cannot be edited.
<span class="text">
Jack Wolfskin Jacke Colorado Flex - Midnight Blue
</span>
<span class="svg">
<svg>
....
</svg>
</span>

add display-block to svg container:
.svg {
display: inline-block;
}

The only solution I found required a nasty change in the origin HTML.
To make sure the icon is never alone in the new line I wrapped the last word and the icon in a new element with white-space: no-wrap;, plus if we want it to still split if the line cannot accommodate last word with the icon we can make this new container inline flex and flex-wrappable.
<div>
Lorem ipsum dolor sit
<span class="last_word">
very_long_last_word
<svg>...</svg>
</span>
</div>
.last_word {
/* Stick icon to last word */
white-space: no-wrap;
/* Make sure last word and icon will break ultimately */
display: inline-flex;
flex-wrap: wrap;
}
Live example: https://jsfiddle.net/uerzo6sa/

You can prevent the line breaking with this markup. It doesn't need to include the last word, so you can use it even with a generated content.
JSX
<div>
{children}
<span className="tail">
{'\u00a0'}
<svg></svg>
</span>
</div>
HTML
<div>
Lorem ipsum dolor sit<span class="tail"> <svg></svg></span>
</div>
CSS
.tail {
white-space: no-wrap;
}
https://jsfiddle.net/radarfox/65h40jt7/

You can add padding to the text and a negative margin:
<span class="text" style="padding-right: 15px;">
Jack Wolfskin Jacke Colorado Flex - Midnight Blue
</span>
<span class="svg" style="margin-left: -15px;">
<svg>
....
</svg>
</span>
That way, if there isn't room for the padding, the last word will get pushed to the next line also.
(This is based on this answer: https://stackoverflow.com/a/25857961/5899236)

You can define position: absolute on the SVG, with auto for top, right, etc.
https://codepen.io/jsit/pen/xxOQoVW
The only side-effect is this will allow the SVG to appear outside of the containing box; this is in a sense the reason it works at all.

Related

Why does a ::before pseudoelement with content have only leading spaces stripped in a 'display: flex' container?

See jsfiddle
Note that both leading and trailing spaces are stripped from each element fairly consistently, except for the pseudo element (::before.content), which only has its leading space trimmed. Why is this? I would expect the trailing space to be removed as well
.flexy {
display: inline-flex;
}
.noname::before {
content: ' has ';
}
<div class="flexy">
A girl
<span class="noname">no name</span>
</div>
<br/>
<div class="flexy">
A girl
<span class="noname"><span>no name</span></span>
</div>
<br/>
<div class="flexy">
Jon Snow
<span> knows </span>
<span>nothing</span>
</div>
To better understand this, let's first add the missing cases.
.flexy {
display: inline-flex;
}
.noname::before {
content: ' has ';
}
.noname-after::after {
content: ' has ';
}
span {
border:1px solid;
}
<div class="flexy">
A girl <span class="noname">no name</span>
</div>
<br>
<div class="flexy">
A girl <span class="noname"><span>no name</span></span>
</div>
<br>
<div class="flexy">
A girl <span class="noname-after"><span>no name</span></span> some text after
</div>
<br>
<div class="flexy">
A girl <span class="noname-after"></span><span>no name</span> some text after
</div>
<br>
<div class="flexy">
Jon Snow
<span> knows </span>
<span>nothing</span>
</div>
We can clearly see that we are missing the leading space when where are using before and the trailing one when using after and both of them if only after (or before) is inside the span.
In other words, we are missing the spaces at the edges of all the <span> elements (with or without the use of pseudo element) and this is logical because it's the default behavior of white-space. From the specification:
As each line is laid out,
If a space (U+0020) at the beginning of a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line', it is removed.
All tabs (U+0009) are rendered as a horizontal shift that lines up the start edge of the next glyph with the next tab stop. Tab stops occur at points that are multiples of 8 times the width of a space (U+0020) rendered in the block's font from the block's starting content edge.
If a space (U+0020) at the end of a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line', it is also removed.
If spaces (U+0020) or tabs (U+0009) at the end of a line have 'white-space' set to 'pre-wrap', UAs may visually collapse them.
Now you will tell me that we are dealing with span elements and we don't have block and new lines but we are inside a flex container thus each element will get blockified and the above rules applies here.
The display value of a flex item is blockifiedref
Worth to note that the pseudo element aren't direct child of the flex container so they are still inline element inside block element .If we change them to block element (using inline-block1 for example) you will see that the spaces will always disappear:
.flexy {
display: inline-flex;
}
.noname::before {
content: ' has ';
display:inline-block;
}
.noname-after::after {
content: ' has ';
display:inline-block;
}
span {
border:1px solid;
}
<div class="flexy">
A girl <span class="noname">no name</span>
</div>
<br>
<div class="flexy">
A girl <span class="noname"><span style="display:inline-block;">no name</span></span>
</div>
<br>
<div class="flexy">
A girl <span class="noname-after"><span>no name</span></span> some text after
</div>
<br>
<div class="flexy">
A girl <span class="noname-after"></span><span>no name</span> some text after
</div>
<br>
<div class="flexy">
Jon Snow
<span> knows </span>
<span>nothing</span>
</div>
Another important thing to note is how flexbox handle spaces:
Each in-flow child of a flex container becomes a flex item, and each contiguous sequence of child text runs is wrapped in an anonymous block container flex item. However, if the entire sequence of child text runs contains only white space (i.e. characters that can be affected by the white-space property) it is instead not rendered (just as if its text nodes were display:none).
Now we can clearly understand what is happening. Inside our flex container we first create the flex items by removing all the extra spaces between them. Then each flex item become a block level element and inside we apply the white space algorithm that removes the trailing and leading spaces inside that block.
You can change the white-space property if you want to keep the trailing and leading spaces:
.flexy {
display: inline-flex;
}
.noname::before {
content: ' has ';
}
.noname-after::after {
content: ' has ';
}
span {
border:1px solid;
white-space:pre;
}
<div class="flexy">
A girl <span class="noname">no name</span>
</div>
<br>
<div class="flexy">
A girl <span class="noname"><span>no name</span></span>
</div>
<br>
<div class="flexy">
A girl <span class="noname-after"><span>no name</span></span> some text after
</div>
<br>
<div class="flexy">
A girl <span class="noname-after"></span><span>no name</span> some text after
</div>
<br>
<div class="flexy">
Jon Snow
<span> knows </span>
<span>nothing</span>
</div>
Here is another example to better understand what is happening step by step:
span {
border:1px solid;
}
div {
border:1px solid red;
margin:10px 0;
}
Spaces are removed from the start and the end, spaces inside are kept (contiguous spaces are collapsed to only one space)
<div>
<span> text inside span </span> text without span<span> text inside span </span>
</div>
I made the last span inline-block so its first space inside is removed
<div>
<span> text inside span </span> text without span<span style="display:inline-block"> text inside span </span>
</div>
Spaces between flex items are removed (We have 3 items and one inside an anonymous block) then first and last space inside each flex items are also removed
<div style="display:flex;">
<span> text inside span </span> text without span<span> text inside span </span>
</div>
We change the white space algorithm and now all the spaces are kept
<div style="display:flex;white-space:pre;">
<span> text inside span </span> text without span<span> text inside span </span>
</div>
1: This value causes an element to generate an inline-level block container. The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box.

Keep div's from pushing each other

The picture is the layout that I want but when you hover, everything gets messed up. The div's start shifting around and moving horizontally when the next div italicizes. How can I maintain this exact layout 100% of the time?
.project-link {
font-family: 'UtopiaStd';
color:#010202;
font-size:5.6vw;
white-space:nowrap;
text-decoration:none;
margin-right: 3%;
line-height:125%;
border-bottom: solid transparent 2px; }
https://jsfiddle.net/zjkouzbo/1/
Solution 1:
You had the right idea with trying white-space:nowrap. To keep your first two links together and keep them on one line, wrap them in a parent element and apply the white-space:nowrap to that parent element. If you have that on both the anchor elements and the parent elements, then you won't break the lines in the middle of a link or between them.
<div class="line">
<a class="project-link" id="one" href="#modal1">Maru speaker design <span> (1) </span> </a>
<a class="project-link" id="two" href="#modal2">Lights — Out <span> (2) </span></a>
</div>
CSS
.line{
white-space: nowrap;
}
New fiddle: https://jsfiddle.net/zjkouzbo/2/
Solution 2:
Place a non-breaking space between the anchor elements that you want to keep on the same line using the HTML entity . Just make sure that you take out any other spaces, including line breaks, between the two elements. This makes your code a little annoying to read, but it doesn't suffer from the "div-itis" that solution one does.
<a class="project-link" id="one" href="#modal1">Maru speaker design <span> (1) </span> </a> <a class="project-link" id="two" href="#modal2">Lights — Out <span> (2) </span></a>
Second fiddle: https://jsfiddle.net/zjkouzbo/3/
Since the <a> tag is an inline element, it will adjust which 'line' it is on as the parent block element changes width, or in your case the link width changes size. If you want to keep a the particular layout where link 1 and 2 are on the same line, but different lines from the rest, you should organize each group in a block element.
<div class="project_miniwrap">
<div class="group-block">
<a>Link 1</a>
<a>Link 2</a>
</div>
<div class="group-block">
<a>Link 3</a>
<a>Link 4</a>
</div>
</div>
adding
display:inline-block
and removing the line breaks you added to project-link solves the issue.
https://jsfiddle.net/70dceskq/1/

Middle alignment of font icon with text on right

Following is my fiddle in which I am trying to vertically align the text with Icon Font. Kindly let me know what's an appropriate way to do such alignment:
How can I vertically align the font icon with the text on this fiddle
Wrong output:
[ICON]Text
Text Text
Expected Output:
Text
[ICON] Text
Text
You can simply make the icon float (bootply #1):
.panel-title .glyphicon {
float: left;
margin-right: 10px;
}
but I prefer using Block Formatting Context (BFC) properties when it comes after a floating element (needs an extra element to enclose your text). It basically creates a column along your float instead of letting your text wrap around it as usual (bootply #2):
HTML:
<a href="#collapseFour">
<span class="left mr1 glyphicon glyphicon-file"></span>
<span class="bfc">Reports Reports Reports Reports Reports Reports Reports</span>
</a>
CSS:
.left {
float: left;
}
.bfc {
overflow: hidden;
}
div it.
put the icon in a separated div, like this:
<div>
{icon}
</div>
<div>
{text}
</div>
and put them inline. display:inline-block... this should work.
you can make a little table like this
<table>
<tr>
<td valign="middle">[ICON]</td><td>Text<br>Text<br>Text</td>
</tr>
</table>

Centring a div box when you cannot adjust html

I am trying to adjust the CSS so the "product" and product information is centered and not floated to the left I cannot adjust the HTML as its given via a shortcode thats added into the WP post but maybe I could wrap it in a div?
HTML:
<ul class="products ribbon">
<li class="product last first">
<a href="http://dailybabydeals.co.nz/shop/estella-rose-designs/">
<div class="thumbnail">
<span class="onsale">Sale!</span>
<img width="325" height="325" src="http://dailybabydeals.co.nz/wp-content/uploads/2013/02/Front-Page-325x325.jpg" class="attachment-shop_catalog wp-post-image" alt="Front Page" />
<div class="thumb-shadow"></div>
<strong class="below-thumb">Estella Rose Designs</strong>
</div>
<span class="price"><span class="from">From: </span><del><span class="amount">$25</span></del> <ins><span class="amount">$19.95</span></ins></span>
</a>
<div class="buttons">
Select options</div>
</li></ul>
CSS:
CSS
Okay, let's try this again now that I understand your question better. So you want to center the <ul> element as a whole? That is a lot simpler than what I originally thought you were going for.
To do that, all you need to do is wrap the <ul> element in a span tag that is set to display as an inline-block. Then set the containing element so that its text is centered.
Try this:
<html>
<head>
<style language="text/css">
/*<![CDATA[ */
#test1 {
text-align: center;
}
#test2 {
display: inline-block;
text-align: left;
}
/* ]]> */
</style>
</head>
<body>
<div id="test1">
<span id="test2">
<!-- Place your <ul> element here -->
</span>
</div>
</body>
</html>
how it works
The "test2" element is set to display as an inline-block, which means it displays inline with the text. This means that it can then be affected by properties that manipulate lines of text, such as "text-align".
Setting "text-align" to "center" on the "test1" element makes the inline content -- the "test2" element in this case -- within it become centered on the screen.
The standard way to center a block is to set the "margin-right" and "margin-left" properties to "auto", but that only works for elements that are displayed as blocks and that have a width that is less than 100%.
I would just put it in a div and float it next to another div with nothing in it.
http://www.barelyfitz.com/screencast/html-training/css/positioning/
Like in step 8 in this link.
The reason that it looks like the text "Sale!" is floated to the left is that <img> elements display as inline blocks by default, so the image is on the same line of text as the words "Sale!". A <br /> tag immediately following the text "Sale!" would solve that problem; but you said you can't modify this HTML, right?
Given that restriction, here is how I was able to solve the problem...
Surround the HTML from your example in a <span> tag and assign it a class. I used "test" as my class name".
Then Place this CSS in the head of the HTML document:
<style language="text/css">
/*<![CDATA[ */
.thumbnail img {
display: block;
}
.test {
display: inline-block;
}
.test .price, .test .below-thumb {
display: block;
text-align: center;
}
/* ]]> */
</style>
why it works
The selector for making the image display as a block solves the problem of the missing <br /> tag.
The span tag with which you surrounded the HTML displays as an inline block. This means that it will collapse around its contents, giving you a box within which you can center the text.
Making the items that contain the text display as a block causes them to take a width of 100%, filling the surrounding box
The inclusion of "text-align: center" is what finally makes the text display as centered within its container

CSS: display:inline-block and positioning:absolute

Please consider the following code:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<style type="text/css">
.section {
display: block;
width: 200px;
border: 1px dashed blue;
margin-bottom: 10px;
}
.element-left,
.element-right-a,
.element-right-b {
display: inline-block;
background-color: #ccc;
vertical-align: top;
}
.element-right-a,
.element-right-b {
max-width: 100px;
}
.element-right-b {
position: absolute;
left: 100px;
}
</style>
<title>test</title>
</head>
<body>
<div class="section">
<span class="element-left">some text</span>
<span class="element-right-a">some text</span>
</div>
<div class="section">
<span class="element-left">some text</span>
<span class="element-right-a">some more text to force line wrapping</span>
</div>
<div class="section">
<span class="element-left">some text</span>
<span class="element-right-b">some text</span>
</div>
<div class="section">
<span class="element-left">some text</span>
<span class="element-right-b">some more text to force line wrapping</span>
</div>
<div class="section">
<span class="element-left">some text</span>
<span class="element-right-b">some more text to force line wrapping</span>
</div>
</body>
</html>
The element with absolute positioning apparantly makes the containing box "forget" which height he needs.
I need the absolute positioning inside the "section" box, is there another solution for this?
edit
Using tables is not really an option, I need some sort of "multi-level"/"nested" layout, where the second col is always on the same position:
| some text in first column | some text in 2nd column
| some indented text | 2nd column
| also indented | 2nd col
| even more indent | 2nd column with a lot of text that
| makes it wrap
| text | ...
| blah blah | ...
(of course whithout the "|"s)
When you use position:absolute;, the element is taken out of the normal page flow. Therefore it no longer affects the layout of its container element. So the container element does not take into account its height, so if there's nothing else to set the height, then the container will be zero height.
Additionally, setting display:inline-block; does not make any sense for an element that is position:absolute;. Again, this is because absolute positioning takes the element out of the page flow. This is at odds with inline-block, which only exists to affect how the element fits into the page flow. All elements that are position:absolute; are automatically treated as display:block, since that's the only logical display mode for absolute positioning.
If you need absolute positioning, then the only solution to your height problem is to set the height of the container box.
However, I suspect that you could do without the absolute positioning.
It looks like what you're trying to do is position the second <span> in each block to a fixed position in the block, so that they line up.
This is a classic CSS problem. In the "bad-old-days", web designers would have done it using a table, with fixed widths on the table cells. This obviously isn't the answer for today's web designers, but it is something that causes a lot of questions.
There are a number of ways to do it using CSS.
The easiest is to set both the <span> elements to display:inline-block;, and give them both a fixed width.
eg:
<div class='section'>
<span class="element-left">some text</span>
<span class="element-right">some text</span>
</div>
with the following CSS:
.section span {display:inline-block;}
.element-left {width:200px;}
.element-right {width:150px;}
[EDIT]after question has been updated
Here's how I would achieve what you're asking now:
<div class='section'>
<span class="element-left"><span class='indent-0'>some text</span></span>
<span class="element-right">some text</span>
</div>
<div class='section'>
<span class="element-left"><span class='indent-1'>some text</span></span>
<span class="element-right">some text</span>
</div>
<div class='section'>
<span class="element-left"><span class='indent-2'>some text</span></span>
<span class="element-right">some text</span>
</div>
with the following CSS:
.section span {display:inline-block;}
.element-left {width:200px;}
.indent-1 {padding:10px;}
.indent-2 {padding:20px;}
.element-right {width:150px;}
A small amount of extra markup, but it does achieve the effect you want.
No.
You could position absolutely then have a copy of the element inside the section box with visible: none but absolute positioning by definition makes it a "floating" element that doesn't interact with elements above it.
Assuming your page layout is fixed you could use padding-left: #px; to achieve your goal, as I don't think relative positioning is what you want.
Alternatively, you could use display: table-* to force it to retain a stricter form without affecting the document structure as shown here
However depending on whether you want the cells to be fluid you may need to alter the .section divs into display: table-row if you don't like a predetermined width setup and want the separate .section's to line up.
This can in fact be done easily and simply with divs. You just need to place a div with position:relative inside the inline or block display div. Set its width and height to the same as the containing div. You will then find you can position another div absolutely inside it.

Resources