Why is my span moving down when I add additional text? - html

I am working on a project that involves a span of text. The span is added to by javascript, for example if I add 'a' to the span, the formatting is fine, but if I add a second character, 'b', both characters and all characters written after that move down about a few pixels, and stay at that line. The span must always display text in the same place, I'm using a monotype font so there's uniform display. I thought maybe the span was wordwrapping or something. Strangely, I've used this same span and code on my Wordpress site with no issues. It's just the standalone html, javascript, and CSS that are having the issue. My current CSS for the span looks like this. I also tried copying the CSS profile from Wordpress but didn't see anything obvious that would be changing where the text position after adding a second character.
#dlpasscode {
display:block;
z-index: 2;
width: 170px;
top: 144px;
left: 120px;
font-family: 'Ubuntu Mono';
font-size: 28px;
color: white;
margin-top:0;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
margin: 0;
padding: 0;
border: 0;
font-size: 28px;
vertical-align: baseline;
white-space:nowrap;
overflow: hidden;}
The javascript I'm calling to display the characters (this is for a UI simulator and each ID is passed in as a character then added to the string).
function dlDisplayPass(lastOptScreen) {
switch (lastOptScreen) {
case dlSim.enterNewPass.src:
case dlSim.confNewPass.src:
passStore = passStore + clicked.id;
jQuery('#dlpasscode').append(clicked.id);
break;
default:
// display up to 9 masked characters, stop and need to display arrow
// allows only up to 32 characters, ignores clicks after that and beeps
if (passStore.length < 32) {
passStore = passStore + clicked.id;
} else {
longbeep.playclip();
}
var passArray = null;
if (passStore.length <= 8) {
passArray = new Array(passStore.length).join(dlpassmask);
}
if (passStore.length === 9) {
passArray = new Array(9).join(dlpassmask);
}
if (passStore.length >= 10 && passStore.length < 32) {
passArray = leftArrow + new Array(8).join(dlpassmask);
}
if (passStore.length < 32) {
jQuery('#dlpasscode').text(passArray).append(clicked.id);
}
}
return false;
}
The actual span just looks like this
<span class="dlbezel dlchild" id="dlpasscode" unselectable ></span>

I figured out updating jQuery updated the issue. Per their website, the jQuery().text() function says "due to variations in the HTML parsers in different browsers, the text returned may vary in newlines and other white space."
Thanks for the help.

Related

How can I center text relative to a single letter of another text?

I have two letters. One is "M" at a very large font. Another is a single-digit number. I want the number to overlap the text and be centered with the M, and for them to stay aligned at the same relative scale at any font size, as if they were one character. I also don't want the number to take up any space in the following line of text. The M should be able to stay inline as well, without causing a line break. Is this possible?
I've been trying to use negative margins scaled by em units, but the two letters still fall out of alignment.
<span style="font-size:200%;"><!-- arbitrary font size for testing to make sure it scales --><span style="margin-right:-1ch;"><span style="font-size:500%; -moz-user-select: none; -khtml-user-select: none; -webkit-user-select: none; user-select: none;">M</span><span style="top:-1px; left:-2em; position:relative; color:blue; display:inline-block;">1</span>
</span></span>test text to make sure the 1 doesn't take up space
Here is the solution I made for you. You can check it's working since I used percentages and em values which both depend on the size of the M-letter. You can play with it and decrease the font-size of .big-letter span and it will all be aligned in any size. Instead of using two spans (two other tags) to form one element, we usually use ::before and ::after selectors.
If you want to preserve the opportunity to modify the value of that number inside that letter, I would recommend using the following structure:
let test = document.getElementById('test');
let fontSize = window.getComputedStyle(test, null).getPropertyValue('font-size');
let increment = document.getElementById('increment');
increment.addEventListener('click', () => {
fontSize = (parseFloat(fontSize) + 4) + 'px';
test.style.fontSize = fontSize;
});
let decrement = document.getElementById('decrement');
decrement.addEventListener('click', () => {
fontSize = (parseFloat(fontSize) - 4) + 'px';
test.style.fontSize = fontSize;
});
#test {
font-size: 16px;
margin-top: 20px;
}
.big-letter {
font-size: 200%;
margin-right: -0.2em;
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
position: relative;
}
.big-letter span {
content: '1';
font-size: 40%;
position: absolute;
bottom: 11%;
left: 40%;
color: blue;
}
#increment {
position: fixed;
top: 10px;
left: 65px;
}
#decrement {
position: fixed;
top: 10px;
left: 155px;
}
<div id="test">
<span class="big-letter">
M
</span>
<span class="big-letter">
M
<span>
2
</span>
</span>
test text to make sure the 1 doesn't take up space
<button id="increment">
increment
</button>
<button id="decrement">
decrement
</button>
</div>
I hope that helped you.
P.S. I updated the snippet that you could see it changing.

How can I scale arbitrary text to always fit the viewport width?

A site I'm busy working on has a section with some very large headings. There's something I'm not sure how to handle:
The heading may be one two short or long words, e.g: "Cyprus" to "Nouvelle Zelande", and it must scale to be roughly the width of the viewport. That means "Cyprus", being shorter, will have larger individual characters than longer text than "Nouvelle Zelande".
This would be relatively easy to do with JavaScript, I think, but I'd like to go for a pure HTML/CSS solution. So: how can I scale text to fit the width of the viewport? So far, I'm stumped and not sure how to do it, myself.
Some details:
You only need to target the most recent version of each browser, which includes IE11.
You may use any and all HTML5 and CSS3 that works within those browsers.
It's okay if you make the text "Nouvelle Zelande" word-wrap, as long as the longer of the two words still roughly fits to the width available.
You may add extra elements inside/around the headings.
Note that viewport units are not a solution. Previous questions asking about this (Pure CSS to make font-size responsive based on dynamic amount of characters, Font scaling based on width of container) have answers of "use viewport units, like vw!", but that doesn't handle this scenario at all, and astute readers even pointed this out. I've even used vw in the code sample below to demonstrate its non-solution-ness. It'll size based on the viewport just fine, but won't do any sizing based on the amount of text.
Code sample
h2 {
font-family: sans-serif;
text-transform: uppercase;
font-size: 14vw;
white-space: nowrap;
overflow-x: hidden;
margin: 0;
}
<h2>Nouvelle Zelande</h2>
<h2>Australia</h2>
<h2>Cyprus</h2>
The only unit, if being used to set font size, that is relative to the size of its container, is viewport units vw/vh, which will not solve your case alone, even if the container is the same width as the viewport, since it does not calc the letter size to fit into the container.
The closest non-script solution I can come up with is to use the CSS element counter trick, and wrap each letter in a span
The 130vw I set here, worked best for the given font, though this might need to be adjusted based on which font family is being used.
h2 {
display: inline-block;
font-family: sans-serif;
text-transform: uppercase;
white-space: nowrap;
overflow-x: hidden;
margin: 0;
}
/* 1 letter */
h2 span:first-child:nth-last-child(1) {
font-size: 130vw;
}
/* skipped 2-5 in this demo */
/* 6 letters */
h2 span:first-child:nth-last-child(6),
h2 span:first-child:nth-last-child(6) ~ span {
font-size: calc(130vw / 6);
}
/* skipped 7-14 in this demo */
/* 15 letters */
h2 span:first-child:nth-last-child(15),
h2 span:first-child:nth-last-child(15) ~ span {
font-size: calc(130vw / 15);
}
<h2><span>N</span><span>o</span><span>u</span><span>v</span><span>e</span><span>l</span><span>l</span><span>e</span> <span>Z</span><span>e</span><span>l</span><span>a</span><span>n</span><span>d</span><span>e</span></h2><br>
<h2><span>C</span><span>y</span><span>p</span><span>r</span><span>u</span><span>s</span></h2>
Here is the same concept using a script, and without the span's
(function (d,t) {
window.addEventListener("resize", throttler, false);
window.addEventListener("load", throttler(), false); /* run once on load to init */
function throttler() {
if ( !t ) {
t = setTimeout(function() {
t = null;
keepTextFit(d.querySelectorAll('h2'));
}, 66);
}
}
function keepTextFit(el) {
var f = el[0].getAttribute("data-font");
for (var i = 0; i < el.length; i++) {
var c = el[i].textContent.split('').length;
el[i].style.cssText =
'font-size: calc(' + f + ' / ' + c + ')';
}
}
})(document,null);
h2 {
display: inline-block;
font-family: sans-serif;
text-transform: uppercase;
white-space: nowrap;
overflow-x: hidden;
margin: 0;
}
<h2 data-font="130vw">Nouvelle Zelande</h2>
<h2>Australia</h2>
<h2>Cyprus</h2>
Note, since resize events can fire at a high rate, the throttler is used to reduced the rate so the handler doesn't execute expensive operations such as DOM modifications too often.
If you want to make a perfect fit, check this post: fit-text-perfectly-inside-a-div
If you are looking to use a plugin there's
http://fittextjs.com/
wich can do that for you

A4 page like layout in html

I am working on small web based application where user is presented 2-3 page long report which can be printed as PDF. I looked at different solutions on stackoverflow / internet and found somewhat working solution to printing side (contents are printed with extra margins but i need to work on that to fix it) my current problem is i am not able to display html content in browser with page like layout. I am able to show 1st page with A4 size but as soon as content goes beyond 1 page it appears as if it printed outside page, you can check the images below
How page is shown in Browser
How it's print preview look like
Here is the CSS
.A4 {
background: white;
width: 21cm;
height: 29.7cm;
display: block;
margin: 0 auto;
padding: 10px 25px;
margin-bottom: 0.5cm;
box-shadow: 0 0 0.5cm rgba(0,0,0,0.5);
}
#media print {
.page-break { display: block; page-break-before: always; }
size: A4 portrait;
}
#media print {
.noprint {display:none;}
.enable-print { display: block; }
}
I am trying to solve below problems,
Would love if all the report is shown with page like layout (additionally, if i can show pages in horizontal pagination instead of long vertical page)
No padding issues while printing, what you see is printed!
Your 2nd problem:
You have to set the body margin and padding to zero. You also need to remove box shadow, margin, width and height from the A4 class in order to print multiple pages.
.A4 {
background: white;
width: 21cm;
height: 29.7cm;
display: block;
margin: 0 auto;
padding: 10px 25px;
margin-bottom: 0.5cm;
box-shadow: 0 0 0.5cm rgba(0, 0, 0, 0.5);
overflow-y: scroll;
box-sizing: border-box;
}
#media print {
.page-break {
display: block;
page-break-before: always;
}
size: A4 portrait;
}
#media print {
body {
margin: 0;
padding: 0;
}
.A4 {
box-shadow: none;
margin: 0;
width: auto;
height: auto;
}
.noprint {
display: none;
}
.enable-print {
display: block;
}
}
Your first problem:
You could try to create a pagination feature by calculating the scrollheight, and keep removing elements from the pages untill the scollheight is smaller than the page itself.
Example: https://jsfiddle.net/tk8rwnav/31/
var max_pages = 100;
var page_count = 0;
function snipMe() {
page_count++;
if (page_count > max_pages) {
return;
}
var long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight());
var children = $(this).children().toArray();
var removed = [];
while (long > 0 && children.length > 0) {
var child = children.pop();
$(child).detach();
removed.unshift(child);
long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight());
}
if (removed.length > 0) {
var a4 = $('<div class="A4"></div>');
a4.append(removed);
$(this).after(a4);
snipMe.call(a4[0]);
}
}
$(document).ready(function() {
$('.A4').each(function() {
snipMe.call(this);
});
});
This example breaks on every element. The paragraphs don't break on words, but you can implement this, but that will get complicated very fast.
Below is a revised version of the snipMe() function to ensure elements in Page 2-n are in the original order. I also added comments.
function snipMe() {
page_count++;
if (page_count > max_pages) {
return;
}
var long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight());
var children = $(this).children().toArray(); // Save elements in this page to children[] array
var removed = [];
// Loop while this page is longer than an A4 page
while (long > 0 && children.length > 0) {
var child = children.pop(); // Remove last array element from the children[] array
$(child).detach(); // JQuery Method detach() removes the "child" element from DOM for the current page
removed.push(child); // Add element that was removed to the end of "removed" array
long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight()); // Compute current size of the page
}
// If elements were removed from the page
if (removed.length > 0) {
var rev_removed = removed.reverse(); // Reverse the order of the removed array
var a4 = $('<div class="A4"></div>'); // Start a new page
a4.append(rev_removed); // Add elements removed from last page to the new page
$(this).after(a4); // Add the new page to the document
snipMe.call(a4[0]); // Recursively call myself to adjust the remainder of the pages
}
}
By default a margin is added for printing aswell. If you click on "More settings" there is a dropdown menu for Margins. select None to remove all margins.
That way you are able to handle the margins within css.

Calculate number of letters and apply CSS

Guys this question is related to this one > Apply CSS to the words in a paragraph written in brackets (parenthesis)
As the databse is not in my control, i'm trying to find some alternatives. Is there a way in CSS to count the number of characters in a sentence and then apply CSS to the rest of the characters?
1ch = width of a "0" (zero)
1ex = height of an "x" (lower case)
ex seems more accurate. Like #BoltClock♦ said, it's not counting, but it's a way to limit the number of characters. I'd try to "do some CSS with the rest" but OP was not specific, and frankly, I have no idea.
Update
The best I can come up with is putting the remaining text in a :after and then style the content.
p.fifteen { max-width: 15ex; outline: 1px solid red; }
p.seventeen { max-width: 15ch; outline: 1px solid red; }
p.fifteen:after { content: 'fghijklmnop'; font-size: 36px; color: red; }
p.seventeen:after { content: 'hijklmnop'; font-variant: small-caps; font-weight: 900; }
<p class="fifteen">123456789abcde</p>
<p class="seventeen">123456789abcdefg</p>
You'll need JavaScript to do that just use somestring.length like so:
var someString= 'abc';
var str = someString.length;
console.log(string);
Result: 3
Check this out for more info http://www.quirksmode.org/js/strings.html
or jQuery method is:
Html
<div id="selector">Some Text</div>
jQuery
$('#selector').text().length;

HTML5 placeholder disappears on focus

Is there a freely available jQuery plugin that changes placeholder behavior to match HTML5 spec?
Before Focus
On Focus Good (Safari)
On Focus Bad (Chrome, Firefox)
You can what your browser does with this simple fiddle.
HTML5 draft spec says:
User agents should present this hint to the user, after having stripped line breaks from it, when the element's value is the empty string and/or the control is not focused (e.g. by displaying it inside a blank unfocused control and hiding it otherwise).
The "/or" is new in current draft so I suppose that's why Chrome and Firefox don't support it yet. See WebKit bug #73629, Chromium bug #103025.
Stefano J. Attardi wrote a nice jQuery plugin that just does that.
It is more stable than Robert's and also fades to a lighter grey when the field gets focused.
See the demo page
Grab it on GitHub
Play with the fiddle
I modified his plugin to read placeholder attribute as opposed to manually creating a span.
This fiddle has complete code:
HTML
<input type="text" placeholder="Hello, world!">
JS
// Original code by Stefano J. Attardi, MIT license
(function($) {
function toggleLabel() {
var input = $(this);
if (!input.parent().hasClass('placeholder')) {
var label = $('<label>').addClass('placeholder');
input.wrap(label);
var span = $('<span>');
span.text(input.attr('placeholder'))
input.removeAttr('placeholder');
span.insertBefore(input);
}
setTimeout(function() {
var def = input.attr('title');
if (!input.val() || (input.val() == def)) {
input.prev('span').css('visibility', '');
if (def) {
var dummy = $('<label></label>').text(def).css('visibility','hidden').appendTo('body');
input.prev('span').css('margin-left', dummy.width() + 3 + 'px');
dummy.remove();
}
} else {
input.prev('span').css('visibility', 'hidden');
}
}, 0);
};
function resetField() {
var def = $(this).attr('title');
if (!$(this).val() || ($(this).val() == def)) {
$(this).val(def);
$(this).prev('span').css('visibility', '');
}
};
var fields = $('input, textarea');
fields.live('mouseup', toggleLabel); // needed for IE reset icon [X]
fields.live('keydown', toggleLabel);
fields.live('paste', toggleLabel);
fields.live('focusin', function() {
$(this).prev('span').css('color', '#ccc');
});
fields.live('focusout', function() {
$(this).prev('span').css('color', '#999');
});
$(function() {
$('input[placeholder], textarea[placeholder]').each(
function() { toggleLabel.call(this); }
);
});
})(jQuery);
CSS
.placeholder {
background: white;
float: left;
clear: both;
}
.placeholder span {
position: absolute;
padding: 5px;
margin-left: 3px;
color: #999;
}
.placeholder input, .placeholder textarea {
position: relative;
margin: 0;
border-width: 1px;
padding: 6px;
background: transparent;
font: inherit;
}
/* Hack to remove Safari's extra padding. Remove if you don't care about pixel-perfection. */
#media screen and (-webkit-min-device-pixel-ratio:0) {
.placeholder input, .placeholder textarea { padding: 4px; }
}
Robert Nyman discusses the problem and documents his approach in his blog.
This fiddle that has all the neccessary HTML, CSS and JS.
Unfortunately, he solves the problem by changing value.
This will not work by definition if placeholder text is itself a valid input.
I found this question by googling out the solution to the same problem. It seems that existing plugins either don't work in elder browsers or hide placeholder on focus.
So I decided to roll on my own solution while trying to combine best parts from existing plugins.
You may check it out here and open an issue if you face any problems.
How about something simple like this? On focus save out the placeholder attribute value and remove the attribute entirely; on blur, put the attribute back:
$('input[type="text"]').focus( function(){
$(this).attr("data-placeholder",$(this).attr('placeholder')).removeAttr("placeholder");
});
$('input[type="text"]').blur( function(){
$(this).attr("placeholder",$(this).attr('data-placeholder'));
});
I wrote my own css3 only solution. See if that fullfills all your needs.
http://codepen.io/fabiandarga/pen/MayNWm
This is my solution:
the input element is set to "required"
an aditional span element for the placeholder is needed. This element is moved on top of the input element (position: absolute;)
with css selectors the input element is tested for validity (required fields are invalid as long as there is no input) and the placeholder is then hidden.
Pitfall: The placeholder is blocking mouseevents to the input! This problem is circumvented by hiding the placeholder element when the mouse is inside the parent (wrapper).
<div class="wrapper">
<input txpe="text" autofocus="autofocus" required/>
<span class="placeholder">Hier text</span>
</div>
.placeholder {
display: none;
position: absolute;
left: 0px;
right: 0;
top: 0px;
color: #A1A1A1;
}
input:invalid + .placeholder {
display: block; /* show the placeholder as long as the "required" field is empty */
}
.wrapper:hover .placeholder {
display: none; /* required to guarantee the input is clickable */
}
.wrapper{
position: relative;
display: inline-block;
}
Maybe you can try with Float Label Pattern :)
See Float labels in CSS