Difference in pixel for same length of characters - html

While working in css I had faced one issue.
The character with same number of length has difference in pixel values.
<html>
<div>
<p><b>WWWWW</b></p>
<p><b>IIIII</b></p>
<p><b>AAAAA</b></p>
</div>
</html>
WWWWW
IIIII
AAAAA
Both has same [5] character length.
How we can adjust them in CSS?

You can use font-family: monospace;
This will use a font that reserves the same horizontal space for each letter, regardless of their actual width
* {
font-family: monospace;
}
<div>
<p><b>WWWWW</b></p>
<p><b>IIIII</b></p>
<p><b>AAAAA</b></p>
</div>
In my example that font will be applied to all text, but you can of course restrict it to particular element/s by using a tag, class or ID selector (or any combined selector you come up with) instead of the * selector in the CSS rule I used.

You can't do it in CSS, the maximum you can specify is font-family: monospace. Here you have a JS solution.
HTML:
<div class="scaled">WWWWWWWWWW</div>
<div class="scaled">IIIIIIIIII</div>
<div class="scaled">AAAAAAAAAA</div>
CSS:
.scaled > span {
display: inline-block;
width: 20px;
border: 1px solid lightgray;
text-align: center;
}
JAVASCRIPT:
$('.scaled').each(function(){
let $scaled = $(this);
let chars = $scaled.text().split('');
let charsSpans = chars.map((char) => $('<span>' + char + '</span>'));
$scaled
.empty()
.append(charsSpans);
});

Related

How to imitate a monospace font with a variable-width font?

I have read CSS - Make sans-serif font imitate monospace font but the CSS rule letter-spacing doesn't seem to be enough:
How to imitate a monospace fixed font from a standard sans-serif font?
This doesn't work perfectly:
.text {
font-family: sans-serif;
letter-spacing: 10px;
}
<div class="text">
ABCDEFGHIJKLMNOPQR<br>
STUVWXYZ0123456789
</div>
letter-spacing just evenly inserts whitespace between all letters (...hence the name).
It won't normalize characters/glyphs to have the same widths.
We would need a css property like letter-width which doesn't exist.
Apart from changing the actual font metrics in a font editor and compiling a new font you could split up all letters into an array of <span> elements via javaScript.
emulateMonospace();
function emulateMonospace() {
let monoWraps = document.querySelectorAll(".toMonospace");
monoWraps.forEach(function(monoWrap, i) {
//remove all "\n" linebreaks and replace br tags with "\n"
monoWrap.innerHTML = monoWrap.innerHTML
.replaceAll("\n", "")
.replaceAll("<br>", "\n");
let text = monoWrap.textContent;
let letters = text.split("");
//get font-size
let style = window.getComputedStyle(monoWrap);
let fontSize = parseFloat(style.fontSize);
//find maximum letter width
let widths = [];
monoWrap.textContent = "";
letters.forEach(function(letter) {
let span = document.createElement("span");
if (letter == "\n") {
span = document.createElement("br");
}
if (letter == ' ') {
span.innerHTML = ' ';
} else {
span.textContent = letter;
}
monoWrap.appendChild(span);
let width = parseFloat(span.getBoundingClientRect().width);
widths.push(width);
span.classList.add("spanMono");
span.classList.add("spanMono" + i);
});
monoWrap.classList.replace("variableWidth", "monoSpace");
//get exact max width
let maxWidth = Math.max(...widths);
let maxEm = maxWidth / fontSize;
let newStyle = document.createElement("style");
document.head.appendChild(newStyle);
newStyle.sheet.insertRule(`.spanMono${i} { width: ${maxEm}em }`, 0);
});
}
body{
font-family: sans-serif;
font-size: 10vw;
line-height: 1.2em;
transition: 0.3s;
}
.monospaced{
font-family: monospace;
}
.letterspacing{
letter-spacing:0.3em;
}
.teko {
font-family: "Teko", sans-serif;
}
.serif{
font-family: "Georgia", serif;
}
.variableWidth {
opacity: 0;
}
.monoSpace {
opacity: 1;
}
.spanMono {
display: inline-block;
outline: 1px dotted #ccc;
text-align: center;
line-height:1em;
}
<link href="https://fonts.googleapis.com/css2?family=Teko:wght#300&display=swap" rel="stylesheet">
<h3 style="font-size:0.5em;">Proper monospace font</h3>
<div class="monospaced">
WiWi</br>
iWiW
</div>
<h3 style="font-size:0.5em;">Letterspacing can't emulate monospaced fonts!</h3>
<div class="letterspacing">
WiWi</br>
iWiW
</div>
<hr>
<h3 style="font-size:0.5em;">Text splitted up in spans</h3>
<div class="toMonospace variableWidth">
ABCDEFGHIJKLMNOPQR<br>
STUVWXYZ0123456789<br>
</div>
<div class="toMonospace variableWidth teko">
ABCDEFGHIJKLMNOPQR<br>
STUVWXYZ0123456789<br>
</div>
<div class="toMonospace variableWidth serif">
This is<br>
not a<br>
Monospace<br>
font!!!
</div>
Each character will be wrapped in a span with an inline-block display property.
Besides all characters are centered via text-align:center.
The above script will also compare the widths of all characters to set the largest width as the span width.
Admittedly, this is not very handy
but this approach might suffice for design/layout purposes and won't change the actual font files.
As illustrated in the snippet:
In monospace fonts the widest letters like "W" get squeezed (not distorted)
whereas the thinner ones like
"i" get visually stretched (e.g by adding bottom serifs).
So proper monospace fonts are completely different and can't really be emulated.
I've spent too much time trying to find a good monospaced font that works with several alphabets and had the look I wanted. These are the solutions I found (in order of recommendation):
Find a monospaced font that you like and use that.
Use a font editor and change all the letters to the same width (there might be a Python program that can do that, but I haven't tried it). But changing a font to monospaced will not look as good, there are a lots of craftsmanship in creating each letter so it will fit properly in the monospaced box.
Use letter-spacing to simulate a simple monospaced font.

Html <font> tag has no effect when css values are set

I am writing an application using JavaScript and some CSS files.
For some reason when some css values are set the html tag has no effect e.g.
color: red; and <font color="blue">.
My app can be bundled with any other project, so I can't change some CSS values ...
A small reproducible code;
<style>
/* I cannot change these values... */
*
{
color: blue;
font-size: 10px;
}
/* I can change these values */
*
{
color: unset;
font-size: unset;
}
</style>
<font color="red" size="20px">
Lorem ipsum
</font>
In this case text should be red and font size should be set to 20px.
I cannot opt out of this html tag because it is added by the browser - these tags are added to editable div...
Any idea?
As has been said, if at all possible, you should replace the font element with modern HTML.
However as a matter of technique, it is possible to achieve what you wanted to do. You can use the "revert-layer" value instead of "unset".
/* I cannot change these values... */
*
{
color: blue;
font-size: 10px;
}
/* I can change these values */
*
{
color: revert-layer;
font-size: revert-layer;
}
<font color="red" size="20px">
Lorem ipsum
</font>
You should also note that size="20px" does not mean that the font-size will be 20px. The "px" is ignored, the "20" will be interpreted as a number, capped to "7" which is the maximum, and converted to a font-size of "xxx-large". This in turn equates to a scaling factor of 3em, so the font-size will be 16px * 3, = 48px.
As suggested #mplungjan I am replacing <font> html tag to <span style="...">.
It works but I think this is pretty ugly solution.
At your point i would just do
<html>
<head>
<style>
.Font {
font-family: Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<p class="Font">With Font</p>
<p>Without Font</p>
</body>
</html>
For more Font styles use this W3 Schools Link

CSS Overwrite issue

I have a CSS-overwriting issue. There is a parent selector for a whole div which sets the styling for all inputs within. I have some inputs in it which I do want to have another styling for. Even though I put these stylings below the parents in the CSS-file, they still can not overwrite the parents css. Please see embedded CSS for further explanation. (I prefer to not use !important).
The CSS that gets applied (defined at the top of CSS-file)
#content #newPost .inner .inputs button {
width: 70%;
height: 50px;
background-color: #F7F9FA;
text-align: center;
margin: 15px 0 0 15%;
cursor: pointer;
border: 1px solid #A0A0A0;
transition: 0.2s;
}
The CSS that should get applied (defined at bottom)
#resultArray .team button {
width: 40px;
height: 100%;
border: none;
background-color: #E3E8E8;
color: #000;
padding: 0;
text-align: center;
margin: 0;
cursor: default;
}
HTML
<div id='newPost'>
<div class='inner'>
<div class='inputs'>
<div id='resultArray'>
<div class='current'><button disabled>1</button><input>
</div>
</div>
<input placeholder='Title'>
<textarea placeholder='Content'></textarea>
<button id='publishPost'>Publish</button>
</div>
So far I got from your CSS and markup code problem is chaining in CSS selection. You can try apply following selector:
#content #newPost .inner .inputs #resultArray button {
width: 40px;
height: 100%;
border: none;
background-color: #E3E8E8;
color: #000;
padding: 0;
text-align: center;
margin: 0;
cursor: default;
}
Also when you try to override long chain CSS selector you should understand properly CSS Selection Precedence rules.
How long is CSS selection chain it's dose not matter if you uderstand following precedence:
In CSS slection every selector have a mathamatical value: each tag = 1, each .class = 10 or pseudo class such as :hover, :active = 10, #id = 100, inline styling = 1000 and for !important = infinity. You can't never override one !important without another !important.
So form your first selection is "#content #newPost .inner .inputs button" = 100 + 100 + 10 + 10 + 1 = 221
But for "#resultArray .team button" = 100 + 10 + 1 = 111
So second selection will never precedence over first selection.
Also for better understanding see here.
you have extra close this div
<div id='resultArray'>
<div class='current'><button disabled>1</button><input>
</div>
</div>
remove this one and
justify you code like:
<div class='inputs'>
<div id='resultArray'>
<div class='current'><button disabled>1</button><input>
</div>
<div class='int'>
<input placeholder='Title'>
</div>
<div class='int'>
<textarea placeholder='Content'></textarea>
</div>
<button id='publishPost'>Publish</button> -->
</div>
than start work : https://jsfiddle.net/yhsLvc7g/1/
edit: wait... also there is no .team class in your html, so that selector points nowhere
--
Your first selector is WAY more specific than the bottom one, so it will be applied despite being above in the cascade flow.
You need to beat the specificity of the 2 ids, 2 classes and 1 tag of the top selector. That's A LOT of specificity, which means you need to use at least 2 ids + at least 2 classes + at least 1 tag to beat it, then the cascade will take over. Setting an additional class (so 2 + 3 + 1) or an additional ID (so 3 + 2 + 1) will beat it too.
So you need to do something ridiculous like
#content #newPost .inner .inputs #resultArray .team button
That being said, your CSS is extremely overqualified, which means you'll encounter issues like these by the millions.
What you should really be doing is changing the first selector (and all those that you have in such fashion) for less specificity, something like
.inner .inputs button
will probably do the trick
Here's a good resource to understanding CSS specificity:

Is it possible to style an html element, so that it won't 'hurt' inner styles

I'm building some sort of framework where the content of the page can be edited with ContentTools. A requirement of ContentTools is that the regions must be parents.
If you try this:
<h1 data-editable data-name="heading">Content</h1>
It wont work as a region has to contain editable block level elements. A way around this is to wrap the tag like so:
<div data-editable data-name="heading">
<h1>Content</h1>
</div>
But I just want to make the text editable, so I automatically wrapped the inner elements in a div. This works but it affects the styles.
Is there a way to make a div 'transparent', so it will inherit all styles?
I tried the following code.
To be clear: In this example I don't write the h1 css, so i have no influence over which styles are used.
$("[data-editable]").wrapInner("<div class='innerWrap'></div>");
/* example h1 css, could be anything */
body > h1{
font-size: 40px;
color: red;
font-family: sans-serif;
border: 3px solid green;
background-color: blue;
padding: 5px;
}
.innerWrap{
all: inherit;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 data-editable data-name="heading">Content</h1>
As you can see some things work. But things like a border will double.
It has to be no difference with or without the innerWrap.
Is it possible to do this with css? It has to work on every css property.
I think you need to wrap the h1 with a div not div with h1.
for eg. .wrapInner() will produce something like
<h1 data-editable="" data-name="heading">
<div class="innerWrap">Content</div>
</h1>
But what you want is
<div data-editable data-name="heading">
<h1>Content</h1>
</div>
So please try with .wrap() instead of .wrapInner()
$("[data-editable]").wrap("<div class='innerWrap'></div>");
h1{
font-size: 40px;
color: red;
font-family: sans-serif;
border: 3px solid green;
background-color: blue;
padding: 5px;
}
.innerWrap{
all: inherit;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 data-editable data-name="heading">Content</h1>
.innerWrap{
all: inherit; /* remove it*/
}
As a default behaviour, if you not specify css props for ".innerWrap" it will look same as parent only
The ability to make an individual element editable standalone as opposed to as part of a collection (e.g in a region) is currently being worked on: https://github.com/GetmeUK/ContentTools/issues/79
There is however a short-term imperfect approach you could try, first change you're HTML as follows:
<h1 data-editable data-name="heading">
<span data-inline data-ce-tag="h1">Content</span>
</h1>
This will make the h1 tag the region and tell ContentTools/Edit to treat the inner span element as a h1 (text) element (thanks to the data-ce-tag).
But the next problem is that if the user hit's return you'll end up with a new paragraph tag inside of your h1 - which we don't want. This is where the data-inline attribute comes in, we need to listen for mount events and if the element mounted has the data-inline attribute we'll modify its behaviour so it can't do certain things which might produce undesirable events:
ContentEdit.Root.get().bind('mount', function(elem) {
// We're only interested in elements that are marked as inline
if (elem.attr('data-inline') === undefined) {
return;
}
// Change the default behaviour of the element
elem.can('drag', false);
elem.can('drop', false);
elem.can('remove', false);
elem.can('spawn', false);
});
You can find out more about modifying behaviours here, along with their current limitations here.

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;