Can CSS values changed relatively? - html

#foo{font-size:14px;}
Now #foo has 14px font size
#foo{font-size:$-2px} // Hypothetical code
Now #foo has 12px font size. (14px - 2px)
Is this possible by any means? To dynamically change the value of a selector.

You can use rem which will refer to the global font-size.
:root
{
font-size : 14px;
}
#foo
{
font-size : calc(1rem - 2px);
}
<div>
I am a 14px text according to the root font-size
</div>
<div id="foo">
I am a 12 pixel text according to the rem font-size
</div>
EXPLANATION
The rem will refer to the global css. So when processing (1rem - 2px), this is actually (14px - 2px).

1. Using calc() method
I don't understand what do you mean by dynamically changed. But to do relative calculation, use calc() method.
Example:
width: calc(100% - 80px);
2. Using preprocessor like SASS
You might also want to check Sass for preprocessing. One of the well supported features are, variables.
You can define variables and do some calculations.
$body-size: 200px;
body {
width: $body-size/2 ;
}
Here is a simple example I created: jsfiddle
Reference: SASS
3. Using jQuery
The OP mentioned about changing the sizes whenever the window size changed. One approach would be using jQuery
$(window).resize(function() {
var width = $(window).width();
var height = $(window).height();
$('#item').width(width);
});
4. Using vw and vh attributes
The OP mentioned about wanting to change the sizes according to the viewport in the comment.
vw and vh is relative to the viewport width and height respectively.
div.responsive {
width: 10vw; /* 10% of viewport width */
height: 10vh; /* 10% of viewport height */
background-color: black; /* Just to make it visible while testing */
}

My $ 2/100.
CSS as of now, doesn't allow cross-browser variables in truest of sense, but you may be interested in this CSS Variables Official Doc.
CSS not supporting variables, is one of the most important reason CSS Preprocessors exist. eg. SASS, LESS.
You can use font-size and then relative em to control some of the elements properties, but its somewhat whaky, and you will end up having to individually specify font-sizes on children elements.
.example {
font-size: 20px;
border-radius: .5em; // 10px (20*.5)
padding: 2em; // 40px (20*2)
}

Related

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

Is there anyway to style html elements through html classes with variables?

I'm just curious to know if it is possible to have specific stylings based on the name of of a class.
For example, Bootstrap 4 has a helper class for margins and padding like:
<div class="m-t-1 p-a-0"></div>
This gives the div 1em of margin to the top, and removes padding from all sides.
I am sure they have pre-styled this class in their CSS to achieve this.
But I am curious if there is a way to use the class as a variable.
for example:
<div class="fs-x"></div>
where x can be any number, this class would then give the styling the font-size: x to the div.
Is this possible to do?
Thanks.
You can use a CSS pre-processor such as SASS or LESS to achieve this however it generates static classes within a specified range below is an example from the SASS documentation:
$class-slug: for !default
#for $i from 1 through 4
.#{$class-slug}-#{$i}
width: 60px + $i
Which emits this CSS:
.for-1 {
width: 61px;
}
.for-2 {
width: 62px;
}
.for-3 {
width: 63px;
}
.for-4 {
width: 64px;
}
All CSS classes must be explicitly defined. So every variation if X would need to exist in a .css file
you can use constant in css for example
$x = 10px;
img{
margin-bottom : $x;
}
but however you can declare variables with this way
:root {
--color-principal: #06c;
}
#foo h1 {
color: var(--color-principal);
}

Enabling CSS for elements from a specific file

I am developing a plugin for an application.
So lets assume that we have to css files,app.css and plugin.css
Content of app.css
.tempClass{
height : 50px;
width : 50px;
}
Content of plugin.css
.pluginTempClass .tempClass{
height : 40px;
}
Now if my plugin adds to the DOM of appliation a
<div class='pluginTempClass'>
<div class='tempClass'>
SOME CONTENT
</div>
</div>
Here for height attribute the .pluginTempClass .tempClass selector has greater specificity so height rule for that gets applied but since this class doesnt define width, width rule of .tempClass of app.css gets applied.Is there anyway to avoid app.css styles being applied to plugin elements added to DOM
You'd need to set a new width in the plugin.css to also overwrite the value for width being used in app.css e.g.
.pluginTempClass .tempClass {
height: 40px;
width: xxx;
}
Where xxx is the width you want. To reset the width you would set it to 'auto'.
consider>
<link rel="stylesheet" href="css/style1.css">
<link rel="stylesheet" href="css/style2.css">
if style2 is providing style for same element as style1, then style2's style spacification will override the style1's.
i suggest to add to the div or other tag inserted by the dom an attribute like
type="added"
in your css, you avoid this attribute
.tempClass:not([type='added']){
...
}
into this demo, try to delete the attribute type and css will be applied
demo

How to target an element with specific css attribute (CSS Only Solution)?

I have an HTML snippet like below:
<div class="status">
<div class="status-icon green">
Online
</div>
</div>
and related css:
.status {
width: 100px;
}
.status-icon {
display: none;
}
My question is:
How can I write a css rule when .status{width=150px} then .status-icon{display: block;}?
Or is there a selector to target specific css rules like attribute selectors?
You cannot write a CSS rule where a property is set depending on whether the value of another property satisfies some condition. This seems to be what you are asking, even though you refer to CSS attributes. (There are no attributes in CSS; there are attribute selectors, but they refer to HTML or XML attributes.)
CSS as currently defined is simply a style sheet language with no programming features (or, let us say, with very limited programming-like features).
If you define status as a percentage (instead of fixed pixels) then you can do this with media queries
like so:
FIDDLE
.status {
width: 20%;
height: 100px;
background: blue;
}
.status-icon {
display: none;
color: white;
}
/* 20% of 750px = 150px */
#media (min-width: 750px) {
.status-icon
{
display: block;
}
}
So now when the viewport width hits 750px+ the status element will be 150px wide and with the media media query we can set .status-icon to block

Div smart width

see fiddle
html
<div class="e" style="left:5px;top:5px;">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbb</div>
<div class="e" style="left:5px;top:100px;">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</div>​
css
.e {
font-size: 10px;
font-family: arial;
background-color: yellow;
position: absolute;
max-width: 300px;
}
you will notice the 2nd div fits the size of the content exactly, but on the first div there's a bunch of empty space to the right of the a's and b's. This is because the div hit its max width of 300px and then wrapped the b's to a 2nd line. The wrapping is good, but then I would expect the div to then shrink back down to the width of the a's so that there's no empty space to the right.
Is it possible to get it to do this?
Tested in Chrome and FF.
​
you may avoid handling the width, as my understanding is that you're looking for a way to break the text in a satisfying manner.
use word-break: break-all, to wrap the text whenever it hits the container's edge.
Example:
demo on jsFiddle
Reference:
the CSS3 word-break property on Mozilla Developer Network
To shrink a div (or any element) to the size of its text content, you can use JavaScript to get a range that contains its contents and get the size of the range using range.getBoundingClientRect():
function sizeElementToContents(el) {
var range = document.createRange();
range.selectNodeContents(el);
var textRect = range.getBoundingClientRect();
el.style.width = textRect.width + "px";
}
But, of course, that only works with Modern browsers. IE8 and IE7 have different methods for working with ranges. Actually, IE7 automatically handles max-width the way you want it to, but when our IE8 code is run to re-size the divs on IE7, it shrinks the divs to 0. To avoid writing code for specific browser versions, this code runs on IE7 and IE8, but includes a little extra logic so that it works on both browser versions:
function sizeElementToContents(el) {
var range, width;
if (document.createRange) {
range = document.createRange();
range.selectNodeContents(el);
width = range.getBoundingClientRect().width;
}
else {
range = document.body.createTextRange();
range.moveToElementText(el);
range.moveStart("character", 1);
width = range.boundingWidth;
var height = range.boundingHeight;
range.collapse();
range.moveEnd("character", 1);
if (range.boundingHeight == height) {
return; // text doesn't wrap, so don't resize
}
}
el.style.width = width + "px";
}
Working demo: http://jsfiddle.net/gilly3/HZRFb/
Forking from Biziclop's solution:
.e {
font-size: 10px;
font-family: arial;
background-color: yellow;
position: absolute;
max-width: 300px;
margin-right:100%;
}
Link to the Fiddle.
Don't ask me why it works, it might break tomorrow, but adding some extreme margin-right seems to solve the problem:
.e {
margin-right: 9999px;
}
See http://jsfiddle.net/2cTga/1/