Wrap text from bottom to top - css

Anybody know how I could wrap the text in reverse order, from bottom to top?
I attached an example image.
[][http://i.stack.imgur.com/RVsIG.jpg]
Instead of breaking the line after it is full and having an incomplete line at the end, I need to brake somehow from bottom to top, so bottom lines are full and top line is incomplete.

I would not recommend using exotic CSS attributes which aren't even in Chrome & Firefox yet. The best cross-browser solution is to handle this in Javascript when the document loads. Here's a sketch of how to do that:
$(function() {
$(".title").each(function(i,title) {
var width = 0;
var originalHeight = $(title).height();
var spacer = $('<div style="float:right;height:1px;"/>').prependTo(title);
while (originalHeight == $(title).height()) {
spacer.width( ++width );
}
spacer.width( --width );
});
});
Working JSFiddle is here: http://jsfiddle.net/zephod/hfuu3m49/1/

6 years later, but fret not! I have found a pure CSS solution!
Turns out you can achieve this result with flexbox, but it's not obvious or very straight forward. This is what I started out with:
I want the header to be "bottom-heavy", the same effect as you describe in the question.
I began by splitting up my string by whitespace and giving them each a <span> parent. By using flex-wrap: wrap-reverse, and align-content: flex-start. You will achieve this:
Oh no! Now the order is messed up! Here comes the trick. By reversing both the order in which you add spans to the HTML and the direction order of flex with 'flex-direction: row-reverse', you actually achieve the "pyramid-shaped" upwards overflow effect you desire.
Here is my (simplified) code, using react and react-bootstrap:
<Row className='d-flex flex-wrap-reverse flex-row-reverse align-content-start'>
{props.deck.name
.split(' ')
.reverse()
.map(word => (
<span className='mr-1'>{word}</span>
))}
</Row>

There is no general css solution for it. You must have to utilize help of any language.
This is one of the solution using PHP:
<?php
$str= "This is what I want to achieve with your help";
$str = strrev($str);
$exp = str_split($str,18);
$str = implode(">rb<", $exp);
echo strrev($str);
?>

Well, if that is depending on the text, then you can try something like a word replacer. For example
var words = "This is what I want to achieve";
var newWords.replace("what", "what <br />"); // note the line break
document.write(newWords);
Here is a fiddle for you: http://jsfiddle.net/afzaal_ahmad_zeeshan/Ume85/
Otherwise, I don't think you can break a line depending on number of characters in a line.

Wrap and Nowrap will be rendered by the client-browser, so you can not force the browser to wrap from bottom to top. but you can do that with javascript or asp.

This is not a formal solution for this problem. But see if this helps.
The HTML CODE
<div id="mydiv">
I can imagine the logic behind the code having to detect what is the last line, detect the div size, and the font size... then measure how many characters it can fit and finally go to the above line and insert the break where necessary. Some font families might make this harder, but trial and error should solve the issue once the basic code is set..
</div>
CSS:
#mydiv
{
width:1000px;
line-height:18px;
font-size:20px;
text-align:justify;
word-break:break-all;
}
Here setting the div width around 50 times that of the font-size will give you the precise result. Other width values or font values might slightly disorient the last line, giving some blank space after the last character.(Could not solve that part, yet).
JQuery:
$(document).ready(function(){
//GET the total height of the element
var height = $('#mydiv').outerHeight();
//Get the height of each line, which is set in CSS
var lineheight = $('#mydiv').css('line-height');
//Divide The total height by line height to get the no of lines.
var globalHeight = parseInt(height)/parseInt(lineheight);
var myContent = $('#mydiv').html();
var quotient = 0;
//As long as no of lines does not increase, keep looping.
while(quotient<=globalHeight)
{
//Add tiny single blank space to the div's beginning
$('#mydiv').html(' '+myContent);
//Get the new height of line and height of div and get the new no of lines and loop again.
height = $('#mydiv').outerHeight();
lineheight = $('#mydiv').css('line-height');
quotient = parseInt(height)/parseInt(lineheight);
myContent = $('#mydiv').html();
}
//get the final div content after exiting the loop.
var myString = $('#mydiv').html();
//This is to remove the extra space, which will put the last chars to a new line.
var newString = myString.substr(1);
$('#mydiv').html(newString);
});

If you already know where you want your breaks to take place just use simple HTML breaks to break your content and have it display the way you want.
<p>This is what<br/>
want to acheive with your help</p>
If you set the breaks manually (and you know where you want them to break) then create them yourself.
You could also try setting separate css width adjustments based on the dimensions of the screen you are seeing the breaking you are not liking and set an #media reference to make the div width smaller to break the text so it doesn't run unevenly across the top of certain size devices.

Use display: inline-block; on the text div.

Related

How to make text area to fit dynamic content completely without any overflow?

This is an angular app (but anyone with css knowledge can help), where there is a text area with dynamic content.
So as the content item.text changes the text area should grow or shrink according to the content to fit the content perfectly without any overflow.
<textarea [value]="item.text" [placeholder]="item.text ? '' : 'Your Text Here...'" class="font-xl font-bold"></textarea>
// dont worry about the placeholder. you can ignore that.
Currently in my case scrollbar appears & it is not shrinking or growing with the dynamic content.
How can I achieve that?
Or if there is a way to convert a regular html <div> to a textarea, you can suggest that too. But prefers a solution for the above one.
I've tried css rules like, max-content fit-content etc... nothing is working out!
Install npm install ngx-autosize
in html add autosize
<textarea autosize [value]="item.text" [placeholder]="item.text ? '' : 'Your Text Here...'" class="font-xl font-bold"></textarea>
then in appmodule
put in imports: [AutosizeModule ],
Demo
This can't be accomplished with just css, it needs JavaScript that has quite a few corner cases and can be tricky. Such as, pasted input, input populated programatically, auto filled input, handling screen size changes correctly, and on and on, and doing so in a way that is reusable and performs well.
Given all that, I recommend using a lib for this.
I've used angular material's plenty of times with no issues, just add material to your project (can be done via angular CLI with ng add #angular/material) and either import the MatInputModule from #angular/material/input or TextFieldModule from #angular/cdk/text-field (TextFieldModule is quite a bit smaller) to the module where you want to use it, then do:
<textarea cdkTextareaAutoSize cdkAutosizeMinRows="5" [value]="item.text" [placeholder]="item.text ? '' : 'Your Text Here...'" class="font-xl font-bold"></textarea>
you can exclude the cdkAutosizeMinRows option and then it will default to 1 row, but you can use that option to set however many minimum rows you'd like to display. You can also use the cdkAutosizeMaxRows option to make it stop growing at a certain number of rows if you wish, otherwise it will grow indefinitely with the content.
blitz: https://stackblitz.com/edit/angular-4zlkw1?file=src%2Fapp%2Ftext-field-autosize-textarea-example.html
docs: https://material.angular.io/components/input/overview#auto-resizing-textarea-elements
https://material.angular.io/cdk/text-field/overview
You can't change the height of the textarea without Javascript. But you can use an editable div instead. In plain HTML something like this would serve the same purpose as an textarea and will resize automatically based on the content.
<div class="font-xl font-bold" contentEditable>Hello World</div>
If you use a <div> which you can edit then it can grow or shrink accordingly.
<div contenteditable="true">This is a div. It is editable. Try to change this text.</p>
The below will loop over the item and compare height to scrollHeight incrementing the height by lineHeight. Then resets the rows once the height is greater than the scroll height
(function () {
const el = document.querySelector('textarea');
dynamicallyResize(el);
el.addEventListener('change', function () { dynamicallyResize(el); });
})();
function dynamicallyResize(el) {
el == undefined && (el = this.target);
const lineHeight = 16;
let i = el.getAttribute('rows'),
height = Math.ceil(el.getBoundingClientRect().height);
el.style.overflow = 'visible'; //triger redraw
while(height < el.scrollHeight) {
height += lineHeight;
i++;
el.setAttribute('rows', i);
}
el.style.overflow = 'auto';
}
<textarea [value]="item.text" [placeholder]="item.text ? '' : 'Your Text Here...'" class="font-xl font-bold" rows="2">Starting text that exceeds the 2 row limit initially placed on this particular text area.</textarea>

Last line of a paragraph contains a single word only [duplicate]

This question already has answers here:
Widow/Orphan Control with JavaScript?
(7 answers)
Closed 8 years ago.
A common problem when working with typography in HTML/CSS is something we call "horunge" in Swedish ("widow" in english).
What it is:
Let's say you have a box with a width of 200px and with the text "I love typograpy very much". Now the text breaks and becomes:
I love typography very
much
As a designer I don't want a word bastard (single word / row). If this was a document/PDF etc. I would break the word before very and look like this:
I love typography
very much
which looks much better.
Can I solve this with a CSS rule or with a javascript? The rule should be to never let a word stand empty on a row.
I know it can be solved by adding a <br /> but that's not a solution that works with dynamic widths, feed content, different translations, browser font rendering issues etc.
Update (solution)
I solved my problem with this jquery plugin: http://matthewlein.com/widowfix/
A simple jQuery / regrex solution could look like the following, if you add the class "noWidows" to the tag of any element that contains text you are worried about.
Such as:
<p class="noWidows">This is a very important body of text.</p>
And then use this script:
$('.noWidows').each(function(i,d){
$(d).html( $(d).text().replace(/\s(?=[^\s]*$)/g, " ") )
});
This uses regex to find and replace the last space in the string with a non-breaking character. Which means the last two words will be forced onto the same line. It's a good solution if you have space around the end of the line because this could cause the text to run outside of an element with a fixed width, or if not fixed, cause the element to become larger.
Just wanted to add to this page as it helped me a lot.
If you have (widows) actually should be orphans as widows are single words that land on the next page and not single words on a new line.
Working with postcodes like "N12 5GG" will result in the full postcode being on a new line together but still classed as an orphan so a work around is this. (changed the class to "noWidow2" so you can use both versions.
123 Some_road, Some_town, N12 5GG
$('.noWidows2').each(function(i,d){
var value=" "
$(d).html($(d).text().replace(/\s(?=[^\s]*$)/g, value).replace(/\s(?=[^\s]*$)/g, value));
});
This will result is the last 3 white spaces being on a new line together making the postcode issue work.
End Result
123 Some_road,
Some_town, N12 5GG
I made a little script here, with the help of this function to find line height.
It's just an approach, it may or may not work, didn't have time to test throughly.
As of now, text_element must be a jQuery object.
function avoidBastardWord( text_element )
{
var string = text_element.text();
var parent = text_element.parent();
var parent_width = parent.width();
var parent_height = parent.height();
// determine how many lines the text is split into
var lines = parent_height / getLineHeight(text_element.parent()[0]);
// if the text element width is less than the parent width,
// there may be a widow
if ( text_element.width() < parent_width )
{
// find the last word of the entire text
var last_word = text_element.text().split(' ').pop();
// remove it from our text, creating a temporary string
var temp_string = string.substring( 0, string.length - last_word.length - 1);
// set the new one-word-less text string into our element
text_element.text( temp_string );
// check lines again with this new text with one word less
var new_lines = parent.height() / getLineHeight(text_element.parent()[0]);
// if now there are less lines, it means that word was a widow
if ( new_lines != lines )
{
// separate each word
temp_string = string.split(' ');
// put a space before the second word from the last
// (the one before the widow word)
temp_string[ temp_string.length - 2 ] = '<br>' + temp_string[ temp_string.length - 2 ] ;
// recreate the string again
temp_string = temp_string.join(' ');
// our element html becomes the string
text_element.html( temp_string );
}
else
{
// put back the original text into the element
text_element.text( string );
}
}
}
Different browsers have different font settings. Try to play a little to see the differences. I tested it on IE8 and Opera, modifying the string every time and it seemed to work ok.
I would like to hear some feedback and improve because I think it may come in handy anyway.
Just play with it! :)
There are also CSS widows and orphans properties: see the about.com article.
Not sure about browser support...
EDIT: more information about WebKit implementation here: https://bugs.webkit.org/buglist.cgi?quicksearch=orphans.
Manually, you could replace the space in between with
I've been looking for ways to dynamically add it in. I found a few, but haven't been able to make it work myself.
$('span').each(function() {
var w = this.textContent.split(" ");
if (w.length > 1) {
w[w.length - 2] += " " + w[w.length - 1];
w.pop();
this.innerHTML = (w.join(" "));
}
});
#foo {
width: 124px;
border: 1px solid #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
<span class="orphan">hello there I am a string really really long, I wonder how many lines I have</span>
</div>

How to fix bottom of layout of 100% height (jQuery Mobile and Google Map)?

I have a layout where I would like the main content area to be 100% height of the remaining space. So I am almost there but the bottom is truncated (which effects zoom and centering). There is 41px from the bottom that is being truncated, which is the measurement of the header area: http://jsfiddle.net/GTscW/
The reason why I know if it cut off is because I do not see the Google map copyright info. Here is the not truncated, but truncates the top (I just removed the top: 41px from #content .inner-content): http://jsfiddle.net/GTscW/1/
How do I subtract 41px from the bottom from the first sample to get the content 100% of the remaining area?
EDIT:
I was able to add just this: $('#content .inner-content').height($(this).height() - $('#header').height()), but really no CSS solution though???
One issue is that it's not easy to mix percentages and pixel measurements, because different screen sizes will behave differently. But it is possible to use API features to get the map to behave the way you want it to, on any size screen.
Make the map 100% of the screen size, so the header obscures part of the map. Suppress the default map controls so they do not appear partially obscured. Create an empty custom control the same size as the header and position it at the top of the map. When the map controls are added back, the custom control pushes them out of their usual place so they look right on the visible map.
var posn=google.maps.ControlPosition; // shorten the reference
// Add empty custom control
var controlDiv = document.createElement('div');
controlDiv.style.width='100%';
controlDiv.style.height='41px';
map.controls[posn.TOP_LEFT].push(controlDiv);
map.controls[posn.TOP_RIGHT].push(controlDiv);
// Add map controls
map.setOptions({
mapTypeControlOptions:{position:posn.RIGHT_TOP},
mapTypeControl:true,
panControlOptions:{position:posn.LEFT_TOP},
panControl:true,
streetViewControlOptions:{position:posn.LEFT_TOP},
streetViewControl:true,
zoomControlOptions:{position:posn.LEFT_TOP},
zoomControl:true
})
http://jsfiddle.net/GTscW/4/
Note 1: Because the map is actually 41px larger than it looks (in your case), the centre-point will be 20px higher than the centre of the viewable map. This may not be worth worrying about. If it is, then dealing with an apparent centre-point is the subject of another question on SO.
Note 2: This method won't work to get a fixed footer, because the Google logo and Terms links are always at the bottom of the map and [currently] don't move to avoid a control.
I edited your fiddle with a solution: http://jsfiddle.net/T2Nkk/
Basically, create a function that looks something like this:
function remainder() {
$("*[height=\"remainder\"]").each(function(index, element) {
var offsetParent;
var target = $(element);
if (element==$("body")[0]) {
offsetParent = $("html");
}
else {
offsetParent = target.offsetParent();
}
var position = target.position();
var heightParent = offsetParent.height();
var extras = target.outerHeight(true)-target.height();
var remainderHeight = heightParent-position.top;
target.height(remainderHeight-extras);
});
}
For the element that you want to occupy the remainder of the page, do this:
<div id="content" data-role="content" height="remainder">
Finally, when your document is ready:
$(document).ready(function() {
remainder();
});
In css only you can try to use a trick : use both top and bottom attributes on position: absolute property like I did on your fiddle : http://jsfiddle.net/GTscW/23/
Don't know if it works everywhere though.

Adjust size based on height (vertical length)

I am doing a div that needs to display the whole content of a text field and adjust the text size dynamically so that it will not overflow.
To get an idea of the problem, look here http://sandbox.littlegraffyx.com/bible/
You can try entering verses at lower left text box using the format GEN 1:1 for "Genesis 1:1"
My problem is when I try to display long verses, they get truncated. I need to change the size based on how long the current text is. Is there some css that can be applied based on text field size?
As mentioned in the comments, it isn't possible to scale text based on the height of its containing element using pure CSS. But here's a small jQuery script I have used in the past when I needed to achieve what you want. It also adjusts the text size when the user resizes the browser window.
HTML:
<p class="quote">
Really long text goes here...
</p>​
CSS:
.quote {
// The largest size to display text at.
font-size: 36px;
}​
JS:
$(window).bind('resize',function(e){
scaleQuote();
});
function scaleQuote(){
var quote = $('.quote');
var winH = $(window).height();
// Reset font size.
quote.css('font-size', '');
// If quote is larger than viewport, reduce font-size until it fits.
while (winH < (quote.height())){
var fontSize = parseInt(quote.css('font-size'), 10);
quote.css('font-size', fontSize-1+'px');
}
}
scaleQuote();​
Demo: http://jsfiddle.net/eCBmc/2/
You can try something like this. It will set input field to 10 character, and if it's bigger it increase it's size.
http://jsfiddle.net/4qjjf/1/
<html>
<body>
<textarea cols="10" rows="1" id="shit"
onkeyup="this.cols=this.value.length>10?this.value.length:10;"></textarea>
</body>
</html>​

is it even possible to expand a (horizontal) list's background with ajax?

I've got a list with list-style-none which needs to be able to add new items to itself via Ajax and have the background expand appropriately when it does. Adding via Ajax is easy, but every solution I try for the background fails me. I don't know if it's even possible; is it? I'm using a grid like this one:
http://jqueryui.com/demos/sortable/#display-grid
Both WebKit and Firebug are showing me skinny, empty bars when I hover over the enclosing divs and/or the enclosing ul tag. It appears that the minute you set a list loose with list-style-none and float:wherever, you give up control over its background. But that can't be right.
This is something I've run into a number of times. The problem is that floated elements aren't part of the normal box model, so they don't cause their parent elements to expand unless their parent elements are also floated. So if possible, float the ul or containing div.
Edit:
See quirksmode for another css-only workaround.
Could you provide a sample of your code? Also, why does the list have display:none set?
For instance, should be as simple as this:
HTML:
<ul id="dest"></ul>
JS:
// Simplified example, most likely wrapped in $.ajax
// This is the AJAX response function
function(data, response) {
var items = json.parse(data);
$.each(items, function() {
// Assumes item has a name property
$('#dest').append($('<li>' + this.name + '</li>'));
});
}
Should be just that simple. You shouldn't need the hide the list initially, as you can simply append list items and have the display update appropriately.
Hope that helps.
You need to explicitly set the width and height for the area.
Check out this link for Horizontal Scrolling: http://valums.com/scroll-menu-jquery/
Here is the script:
$(function(){
//Get our elements for faster access and set overlay width
var div = $('div.sc_menu'),
ul = $('ul.sc_menu'),
// unordered list's left margin
ulPadding = 15;
//Get menu width
var divWidth = div.width();
//Remove scrollbars
div.css({overflow: 'hidden'});
//Find last image container
var lastLi = ul.find('li:last-child');
//When user move mouse over menu
div.mousemove(function(e){
//As images are loaded ul width increases,
//so we recalculate it each time
var ulWidth = lastLi[0].offsetLeft + lastLi.outerWidth() + ulPadding;
var left = (e.pageX - div.offset().left) * (ulWidth-divWidth) / divWidth;
div.scrollLeft(left);
});
});
Basically, you need to update the ulWidth and divWidth when you add the new item.
Then just set the background image to repeat horizontally and you should be set.
ul.sc_menu {background:transparent url(image.png) repeat scroll 0 0;height:100px}
Note: You will need to set the height; otherwise you will not see the background because the li are floated.
For dealing with the float element, maybe you should know it's characteristic, gotcha, and how to deal with it.
See the links below, it also have demo, so you can understand the concept:
http://www.smashingmagazine.com/2009/10/19/the-mystery-of-css-float-property/
http://www.smashingmagazine.com/2007/05/01/css-float-theory-things-you-should-know/
http://aloestudios.com/2009/12/goodbye-overflow-clearing-hack/
and
http://aloestudios.com/misc/overflow/

Resources