Small update
Note: Target is mainly Chrome (perhaps Firefox) – as it is for an extension. But, of course, if there is an all-round solution that would be nice to know as well.
Another update
Note: Noticed that if there are no spaces in the text for A and it is too big, it pushes out B. Problem became worse and looks like I'm further from a solution then first thought. Updated sample code to allow input from user. Try sample without spaces.
I am having a fixed positioned box of full width and fixed height. It is placed inside an environment of variable / dynamic width.
+-----------------------------+
| |
| |
[=============================] << The box.
| |
| |
...
<- dynamic width ->
The box has two main children A and B. B takes precedence on width and are to hold all of it contents on given height, but not in a greedy way. A is eats remainder of space in a greedy fashion. On text-overflow in A, ellipsis should be added – and that is where I'm stuck.
Some examples.
1. B fills it's space, A expand to fill width.
+-------------------+--------+
| A________ | __B___ |
+-------------------+--------+
2. A has overflow, ellipsis added.
+-------------------+--------+
| A_____________... | __B___ |
+-------------------+--------+
3. B, has grown, A shrinks.
+----------------+-----------+
| A__________... | __B______ |
+----------------+-----------+
After fiddling around with various approaches from floats to absolute, relative and other types I finally landed on a table layout (as in CSS-table, not HTML). Can't get desired effect with other approach. If anyone know how it is OK to tell :)
Problem is the ellipsis part on overflow in A.
Can I somehow tweak e.g. how A is set up to get this?
Sample code:
Ignore the JavaScript, it is only a convenience routine to display the over and under-flow. (Found it nice to have whilst editing in Firefox's Style Editor)
/* Yes. It is all a mess and weird usage of variables vs this etc. */
function Hack() {
var x = 0,
n = 150,
wrap = document.querySelector('#wrap'),
left = document.querySelector('#left'),
right = document.querySelector('#right'),
txt = document.querySelector('#txt'),
ent = document.querySelectorAll('.entry'),
log = document.querySelector('#log'),
run = document.querySelector('#run'),
rt = document.querySelector('#rt'),
samp = document.querySelector('#sample'),
t = samp.value
;
this.rt = parseInt(rt.value) || 1000;
function getComp(e) {
var x = window.getComputedStyle(e, null);
return ''+
~~(parseInt(x.getPropertyValue('height'))) + 'x' +
~~(parseInt(x.getPropertyValue('width')))
;
}
this.status = function () {
log.textContent = 'Height / Width for:\n' +
' wrap : ' + getComp(wrap) + '\n' +
' left : ' + getComp(left) + '\n' +
' right : ' + getComp(right) + '\n' +
' sample: ' + getComp(txt) + '\n'
;
}
/* Change between long and short text in sample cells. */
this.flip = function () {
txt.textContent = x ? t : (new Array(n)).join(t);
Array.prototype.forEach.call(ent, function (e) {
e.textContent = x ? 'abc' : 'abcabc';
});
x ^= 1;
this.status();
}
/* Toggle auto run. */
this.update = function () {
t = samp.value;
this.rt = parseInt(rt.value);
if (!this.rt || this.rt < 10)
rt.value = this.rt = 100;
clearInterval(this.ttt);
if (run.checked)
this.ttt = setInterval(this.flip.bind(this), this.rt);
}
document.addEventListener('click', this.flip.bind(this));
run.addEventListener('click', this.update.bind(this));
rt.addEventListener('change', this.update.bind(this));
samp.addEventListener('keyup', this.update.bind(this));
this.update();
}
window.addEventListener('load', function () {
var hack = new Hack();
hack.flip();
});
* { margin : 0; padding : 0; }
#log { margin : 5pt; border : 1px solid #ccc; }
#filler { margin-top : 90px; height : 2000px; background : #efefef; }
label,
input { cursor : pointer; }
/* inner elements of cells in right -- (B) */
.hdr,
.entry { padding : 2px 5px; }
.hdr { font-weight: bold; }
#wrap { /* the red thing -- aka (the box) */
position : fixed;
top : 135px;
height : 23px;
background : #600;
color : #999;
height : 20px;
width : 100%;
display : table-row;
}
#left { /* the green thing -- aka (A) */
background : #044;
display : table-cell;
width : 100%;
}
#txt { /* sample text in left */ /* Where I want ellipsis */
display : block;
height : 20px;
width : 100%;
overflow : hidden;
text-overflow: ellipsis;
}
#right { /* the purple / blue thing -- aka (B) */
background : rgba(0,0,200,.5);
height : 20px;
display : table-cell;
width : 100%;
white-space: nowrap;
}
<p>Click document to expand text, or auto-run:</p>
<div>
<input type="checkbox" id="run" checked /><label for="run">Change every </label>
<input type="number" id="rt" value="1000" step="100" /> millisecond.
Sample text: <input type="text" value=" sample" id="sample" />
</div>
<pre id="log"></pre>
<!-- The box -->
<div id="wrap">
<div id="left">
<span id="txt">sample <!-- ellipsis here --> </span>
</div>
<div id="right">
<span class="hdr">Foo</span><span class="entry">abcd</span>
<span class="hdr">Bar</span><span class="entry">abcd</span>
</div>
</div>
<!-- EOF: The box -->
<div id="filler">dummy filler page height</div>
Is using Javascript ok?
text-overflow only works in table cells if there is a fixed width. The following snippet sets the max-width of the span to the correct width.
Place this in your flip function and in a resize event listener (if the containing div does not have a fixed width).
txt.style["max-width"] = "calc(" + wrap.clientWidth + "px - " + right.clientWidth +"px)";
Youu will also have to add white-space: nowrap to your #txt style.
function Hack() {
var x = 0,
n = 150,
t = 'sample ',
wrap = document.querySelector('#wrap'),
left = document.querySelector('#left'),
right = document.querySelector('#right'),
txt = document.querySelector('#txt'),
ent = document.querySelectorAll('.entry'),
log = document.querySelector('#log'),
run = document.querySelector('#run'),
rt = document.querySelector('#rt')
;
this.rt = parseInt(rt.value) || 1000;
function getComp(e) {
var x = window.getComputedStyle(e, null);
return ''+
~~(parseInt(x.getPropertyValue('height'))) + 'x' +
~~(parseInt(x.getPropertyValue('width')))
;
}
this.status = function () {
log.textContent = 'Height / Width for:\n' +
' wrap : ' + getComp(wrap) + '\n' +
' left : ' + getComp(left) + '\n' +
' right : ' + getComp(right) + '\n' +
' sample: ' + getComp(txt) + '\n'
;
}
/* Change between long and short text in sample cells. */
this.flip = function () {
txt.textContent = x ? t : (new Array(n)).join(t);
Array.prototype.forEach.call(ent, function (e) {
e.textContent = x ? 'abc' : 'abcabc';
});
txt.style["max-width"] = "calc(" + wrap.clientWidth + "px - " + right.clientWidth +"px)";
x ^= 1;
this.status();
}
/* Toggle auto run. */
this.toggle = function (r) {
this.rt = parseInt(rt.value);
if (!this.rt || this.rt < 10)
rt.value = this.rt = 100;
clearInterval(this.ttt);
if (run.checked)
this.ttt = setInterval(this.flip.bind(this), this.rt);
}
document.addEventListener('click', this.flip.bind(this));
run.addEventListener('click', this.toggle.bind(this));
rt.addEventListener('change', this.toggle.bind(this, 1));
this.toggle();
}
window.addEventListener('load', function () {
var hack = new Hack();
hack.flip();
});
* { margin : 0; padding : 0; }
#log { margin : 5pt; border : 1px solid #ccc; }
#filler { margin-top : 90px; height : 2000px; background : #efefef; }
label,
input { cursor : pointer; }
/* inner elements of cells in right -- (B) */
.hdr,
.entry { padding : 2px 5px; }
.hdr { font-weight: bold; }
#wrap { /* the red thing -- aka (the box) */
position : fixed;
top : 135px;
height : 23px;
background : #600;
color : #999;
height : 20px;
width : 100%;
display : table-row;
}
#left { /* the green thing -- aka (A) */
background : #044;
display : table-cell;
width : 100%;
}
#txt { /* sample text in left */ /* Where I want ellipsis */
display : block;
height : 20px;
width : 100%;
overflow : hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#right { /* the purple / blue thing -- aka (B) */
background : rgba(0,0,200,.5);
height : 20px;
display : table-cell;
width : 100%;
white-space: nowrap;
}
<p>Click document to expand text, or auto-run:</p>
<div>
<input type="checkbox" id="run" checked /><label for="run">Change every </label>
<input type="number" id="rt" value="1000" step="100" /> millisecond.
</div>
<pre id="log"></pre>
<!-- The box -->
<div id="wrap">
<div id="left">
<span id="txt">sample <!-- ellipsis here --> </span>
</div>
<div id="right">
<span class="hdr">Foo</span><span class="entry">abcd</span>
<span class="hdr">Bar</span><span class="entry">abcd</span>
</div>
</div>
<!-- EOF: The box -->
<div id="filler">dummy filler page height</div>
Related
I want to bind text font-size with text length (in <p> with fixed width for example). Expected result is text fit in one line if it is only one word. If there are few words, it can be few lines.
I want to reduce font-size if word is too long for fixed-width line. For example, if "abc" fit in line I want to do nothing, if "abcdefg" doesn't fit in line I want to reduce text font-size
You can use a simply div setting your personal width, inside set your text, in css use
display: flex;
flex-wrap: wrap;
That way the text will respect your div width and brake line in your text when necessary
flex-wrap
Hope this answer will satisfy your question.
The resizing part, which is the most important, is creditted to Jan Küster, with "Make text fit its parent size using JavaScript" article that you can find online.
document.getElementsByTagName("input")[0].onkeyup = execute;
function execute() {
let value = document.getElementsByTagName("input")[0].value;
let words = value.split(" ");
var html = "";
for (var i = 0; i < words.length; i++) {
html += ' <div class="text-container"><span class="text">' + words[i] + '</span></div>';
document.getElementsByClassName("parent")[0].innerHTML = html;
}
resizeText({
elements: document.querySelectorAll('.text'),
step: 0.25
})
}
//
const isOverflown = ({
clientWidth,
clientHeight,
scrollWidth,
scrollHeight
}) => (scrollWidth > clientWidth) || (scrollHeight > clientHeight)
const resizeText = ({
element,
elements,
minSize = 10,
maxSize = 512,
step = 1,
unit = 'px'
}) => {
(elements || [element]).forEach(el => {
let i = minSize
let overflow = false
const parent = el.parentNode
while (!overflow && i < maxSize) {
el.style.fontSize = `${i}${unit}`
overflow = isOverflown(parent)
if (!overflow) i += step
}
// revert to last state where no overflow happened
el.style.fontSize = `${i - step}${unit}`
})
}
body {
background: #A33;
}
.parent {
margin: 2%;
width: 150px;
height: auto;
min-height: 50px;
padding: 15px;
color: white;
display: block;
}
.text-container {
width: 100%;
height: 100%;
}
.text {
font-size: 12px;
display: block;
}
<input type="text">
<div class="parent">
</div>
You could check out Bootstrap 5, they now have responsive text incorporated.
You could also use media queries that change the text size when the screen size is smaller or larger:
/* If the screen size is 601px wide or more, set the font-size of div to 80px */
#media screen and (min-width: 601px) {
div.example {
font-size: 80px;
}
}
/* If the screen size is 600px wide or less, set the font-size of <div> to 30px */
#media screen and (max-width: 600px) {
div.example {
font-size: 30px;
}
}
A final option would be to use the viewport width as the font size. Viewport is the browser window size. 1vw = 1% of viewport width. If the viewport is 50cm wide, 1vw is 0.5cm. Here's an example:
<h1 style="font-size:8vw;">Hello World</h1>
<p style="font-size:2vw;">Resize the browser window to see how the font size scales.</p>
I want to align the text with "=" sign, as of the picture below:
I can do it using mathjax but I want to make it using css if possible. But the way I did it is not making the equals to sign aligned one to another. I want your help.
This is what I tried,
Solution, <br>
Given, f(x) = 3x <br>
g(x) = x + 2 <br>
fog(x) = 18 <br>
To find: x = ?, <br>
Now, <br>
fog(x) = 18 <br>
or, f(x + 2) = 18 <br>
or, 3(x + 2) = 18 <br>
or, x + 2 = 6 <br>
∴ x = 4
You can use display, text-align and width in your classes:
.c-left{
text-align: right;
width: 50px;
display: inline-block;
}
.c-mid{
text-align: center;
width: 10px;
display: inline-block;
}
.c-right{
text-align: left;
width: 50px;
display: inline-block;
}
<div>
<div class="c-left">a + b</div>
<div class="c-mid">=</div>
<div class="c-right">c</div>
</div>
<div>
<div class="c-left">2a + 2b</div>
<div class="c-mid">=</div>
<div class="c-right">3c</div>
</div>
Not sure if this is what you need...
Your problem is arranging the text into a form that's easily style-able using CSS.
Assuming your text comes in the form of a JSON array of strings, i.e:
[
"Solution,",
"Given, f(x) = 3x",
"g(x) = x + 2",
"fog(x) = 18",
"To find: x = ?,",
"Now,",
"fog(x) = 18",
"or, f(x + 2) = 18",
"or, 3(x + 2) = 18",
"or, x + 2 = 6",
"∴ x = 4"
]
...you want a function which turns it into style-able markup.
Here's an example using vanilla Javascript and CSS grid:
[...document.querySelectorAll('math-element')].forEach(el => {
// reset, in case you run this more than once...
el.innerHTML = '';
// we need JSON.parse as dataset.text is a string
JSON.parse(el.dataset.text).forEach(text => {
const div = document.createElement('div');
// split each row by `=` sign, if it has any
text.split('=').forEach(t => {
const span = document.createElement('span');
if (text.split('=').length < 2) {
// adds `.single` to items which are single on their row
span.classList.add('single');
}
span.innerHTML = t;
el.appendChild(span);
});
// add a `<hr>` after each element
const separator = document.createElement('hr')
el.appendChild(separator);
})
})
math-element {
display: grid;
grid-template-columns: auto 1fr;
}
math-element hr {
display: none;
}
math-element span {
grid-column-start: 1;
text-align: right;
padding: 0 2px 0 1rem;
}
math-element span:not(.single) {
font-style: italic;
}
math-element span.single {
text-align: left;
padding-top: .5rem;
font-style: normal;
}
math-element span + span {
grid-column-start: 2;
text-align: left;
padding: 0 2px;
}
math-element span + span:before {
content: '=';
}
<math-element data-text='["Solution,","Given, f(x) = 3x","g(x) = x + 2","fog(x) = 18","To find: x = ?,","Now,","fog(x) = 18","or, f(x + 2) = 18","or, 3(x + 2) = 18","or, x + 2 = 6","∴ x = 4"]'></math-element>
You don't have to inline the value as a string, as I did, you can simply create the element(s) on the fly and run the forEach directly on the data instead.
If you find CSS grid syntax and logic confusing, you can always create a <table> with <tr> and <td>s, which will give you simpler selectors. Out of principle, I advise against it.
I used <hr>s to mark the end of each "row" (CSS grid requires all cells to be siblings). Instead, you could just nest the row contents into a single element (<div> ?) and hard-code the column widths.
Obviously, the CSS is yours to modify (i.e: remove font-style's, adjust the padding values, etc...).
A final note: if one "row" contains more than one = sign, because of this rule:
math-element span + span {
grid-column-start: 2;
}
spans 2 and 3 in a row (and subsequent, until end of row) will be displayed one below each other, each prefixed with a = sign and aligned with the rest (which is not that bad, IMHO). If you want to change this behavior, you probably want to provide a
math-element span + span + span {
grid-column-start: 3;
}
... rule, and so on. Also you'll need to change grid-template-columns to match:
math-element {
grid-template-columns: auto auto 1fr;
}
...matching the number of "columns".
(Originally : To transform or not to transform)
I wanted to start spinning the DIV box so it would spin behind the text boxes. BECAUSE the text boxes did not seem to care what I did with the DIV I just made the javascript spin the DIV. To my surprise - by spinning the DIV the text boxes spun with the DIV and when they went outside of the DIV boxes area - they are now clipped. If I comment out the transforms the text boxes go back to ignoring anything I do with the DIV. So ideas why it is doing this? Do I maybe have to always do a transform and just set the degrees to zero(0)? Ideas and comments are welcome. :-) Here is the code:
PS: I put in the BODY's "overflow:hidden;" because I was testing that out too. Just a FYI. :-)
<html>
<head>
<title>Test</title>
<style>
.p1 { position:absolute;
top:50px;
left:50px;
border: 1px solid grey;
padding: 5px;
font-family: sans-serif,Arial,Helvetica,Verdana,"Trebuchet MS",Tahoma,"MS Sans Serif",Geneva;
font-size: 12pt;
width: 150px;
height: 10pt;
overflow: hidden;
z-index:0;
}
</style>
</head>
<body style='overflow:hidden;'>
<div id='d1' name='d1' style="width:500px;height:400px;overflow:hidden;z-index:1;
border:1px solid black;clip: rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px);">
<p id='p1' name='p1' class='p1'>This is a test of how HTML works</p>
<p id='p2' name='p2' class='p1'>This is a test of how HTML works</p>
<p id='p3' name='p3' class='p1'>This is a test of how HTML works</p>
</div>
<script>
function moveIt(n)
{
document.getElementById("p1").style.left = n;
document.getElementById("p2").style.top = n;
document.getElementById("p3").style.left = n;
document.getElementById("p3").style.top = n;
// document.getElementById("d1").style.transform = "rotate(" + n + "deg)";
if( n < 2000 ){ setTimeout("moveIt(" + (n + 1) + ")", 1 ); }
else { moveIt2(n); }
}
function moveIt2(n)
{
document.getElementById("p1").style.left = n;
document.getElementById("p2").style.top = n;
document.getElementById("p3").style.left = n;
document.getElementById("p3").style.top = n;
// document.getElementById("d1").style.transform = "rotate(" + n + "deg)";
if( n > -1000 ){ setTimeout("moveIt2(" + (n - 1) + ")", 1 ); }
else { moveIt(n); }
}
moveIt(50);
</script>
</body>
</html>
A CSS transform on a parent element affects all the parent's children. That's why the text rotates.
You can prevent their rotation by applying a negative rotation equal in amount to the parent's positive rotation.
Also: You need to supply units such as px when setting the position of elements, like this:
document.getElementById('p1').style.left = n + 'px';
Working Fiddle
I have a div that has the following CSS:
.div_stuff {
width: 830px;
margin: 20px auto;
font-size:22px;
}
How do I prevent the text that goes to the next line to not align left right under the text above but simply become centered on the next line?
Although I'm not sure if I understood what you want to achieve and I can't find a use case for this... Changing the alignment from the second line on would be possible by adding some span tags with javascript/jQuery (DEMO):
$(function() {
var box = $('.div_stuff');
var text = box.text();
var words = text.split(' ');
box.text(words[0]);
var height = box.height();
var chars = 0;
for(var i = 1; i < words.length; i++){
box.text(box.text() + ' ' + words[i]);
chars += words[i-1].length + 1;
if(box.height() > height){
height = box.height();
box.html('<span class="first-line">' + text.substring(0,chars) + '</span><span class="following-lines">' + text.substring(chars+1, text.length)+'</span>');
break;
}
}
});
And set a different alignment to them:
span {
display: block;
}
.first-line {
text-align: left;
}
.following-lines {
text-align: center;
}
I've used that answer for determining auto line breaks.
Add text-align: center to center the text inside. You are centering the div position only.
you can try css3 text justified
http://www.w3schools.com/cssref/css3_pr_text-justify.asp
I'm trying to create a page layout like This
But I am not sure how to achieve it. What I mean; in that page you can see there are two areas in the page and you can resize the areas using the bar between them.
Thanks!
Yes, it's certainly possible. There's probably a JQuery or MooTools plugin out there that does it. Otherwise, I rolled you a simple example using JQuery that you can play with. See this JSFiddle.
Basically the HTML is like this:
<div id="left">Left column!</div>
<div id="verticalresizer"> </div>
<div id="right">Right column!</div>
And then they are positioned absolutely (extra CSS from example cut for simplicity's sake):
html, body {
height: 100%;
}
#left {
width: 200px; /* default starting width */
position: absolute;
top: 0;
bottom: 0;
left: 0;
}
#right {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 204px; /* width of left col + 4 pixel wide resizer */
}
#verticalresizer {
background-color: black; /* so it can be seen */
width: 4px;
height: 100%;
cursor: col-resize;
position: absolute;
top: 0;
left: 200px; /* width of left col */
bottom: 0;
}
Then the JavaScript. First an explanation. Pretty much the code listens for the user to click down on the vertical resizer. Once that happens, it listens for the mouse moving. Every time the mouse moves, resize the columns accordingly and keep the slider underneath the mouse. When the user lets go of the mouse (mouseup), stop listening/resizing.
var left = 200; // starting left col width
var isClicked = false;
var startX = 200; // starting horizontal position of resizer bar
var isMouseDown = false;
// attach listeners to the document itself
$(document).mousedown(function() {
isMouseDown = true;
}).mouseup(function() {
isMouseDown = false;
}).mousemove( function(event) {
if (isClicked && isMouseDown) {
var newX = event.pageX;
if (startX != newX) {
left += (newX - startX);
if (left < 0) {
left = 0; // keep from moving the slider beyond the left edge of the screen
newX = 0;
}
setWidthOfLeftColumn( left );
startX = newX;
}
}
});
// attach click listeners to the resizer slider
$("#verticalresizer").mousedown( function(event) {
isClicked = true;
startX = event.pageX;
}).mouseup( function (event) {
isClicked = false;
});
// function to resize everything
function setWidthOfLeftColumn( value ) {
$("#left").css("width", "" + left + "px");
$("#right").css("left", "" + (left + 4) + "px");
$("#verticalresizer").css("left", "" + left + "px");
}
Try using the HTML frameset tag.
http://www.w3schools.com/tags/tag_frameset.asp