Unexpected effects of LESS calc() function - html

This code:
index.htm.twig
<div id="myBar">Hello</div>
<div id="myDiv">{VERY_LONG_LOREM_IPSUM}</div>
pure style.css
#myBar {
height: 40px;
}
#myDiv {
height: calc(100% - 40px); // document height - #myBar height
}
Everything is OK here.
But when I change pure style.css to style.less:
style.less
#myBar {
height: 40px;
}
#myDiv {
height: calc(100% - 40px); // document height - #myBar height
}
The function calc(100% - 40px); is compiled to calc(60%); in style.css.
I expected the same value like in pure style.css file.
How to fix this issue?

LESS Documentation - String Functions - Escaping
CSS escaping, replaced with ~"value" syntax.
When you're using LESS, you need to escape it, otherwise the numbers will be evaluated, as you are seeing. In this case, you would use calc(~"100% - 40px"):
#myDiv {
height: calc(~"100% - 40px");
}

Related

Override PrimeNG component CSS

I am using PrimeNG OverlayPanel to be displayed in dropdown click but I have a problem to move default left arrow to right position. I tried everything that was in my mind but I am out of ideas.
Can you please give me some new idea for resolving this issue?
code example: https://stackblitz.com/edit/primeng-overlaypanel-demo
dropdown arrow image
Your goal is override deeply incapsulated CSS. One of the possible sollution is to add an id to overlay-panel and then ovverride the desired element(in our case this is before and after pseudo-elements of a div with the p-overlay class
html:
<p-overlayPanel #op [showCloseIcon]="true" id='hello'[style]="{width: '450px'}">
css:
:host ::ng-deep #hello .p-overlaypanel::before,
:host ::ng-deep #hello .p-overlaypanel::after
{
left: 80%;
}
left: 80% is for example.
stackblitz
Add this to style.css:
.p-overlaypanel:after, .p-overlaypanel:before{
left: unset !important;
right: 1.25rem !important;
}
Now the arrow is on the right side opposite of initial.
Additional info: avoid using :host ::ng-deep as it is deprecated.. use the style.css file instead!
.mybutton .p-overlaypanel:after, .mybutton .p-overlaypanel:before {
bottom: 100%;
content: " ";
height: 0;
right: 1.25rem; //<---
pointer-events: none;
position: absolute;
width: 0;
}
is the place but the question is;
how you wish to handle button positioning on page. If button near left,right,bottom border then you should handle arrow position. by this variable.
Convert your entire Angular project to Scss. The reason is that View styles do not go deep. Scss in root does go deep and is worth it long term to stop using just CSS in Angular projects. I wrote an article on this.
For p-overlaypanel
:before and :after are the attributes you should catch for this to work
body .p-overlaypanel:before {
left: calc(100% - 17px);
}
body .p-overlaypanel:after {
left: calc(100% - 17px);
}
You can override it in global stylesheet ie style.scss
by wrapping the elements with a custom class. This will provide more specificity.
.your-class {
.p-overlaypanel:before {
left: calc(100% - 17px);
}
.p-overlaypanel:after {
left: calc(100% - 17px);
}
}

Sass Mixin value is not getting passed on calling from #include

I have couple of partials(say _one.scss and _two.scss) which am calling into a SASS. _one.scss has following code
#mixin wire($num) {
.parts-field {
height: 100%;
width: calc(100% * (1/$num) - 10px - 1px);
}
And in _two.scss has
.mytry {
#include wire(3);
}
In my main.scss am doing the following
#import "../../base/_one.scss";
#import "_two.scss";
When I check main.css, it shows the following:
.mytry .parts{
height: 100%;
width: calc(100% * (1/$num) - 10px - 1px);
}
Even though am saying #include wire(3), I believe the 3 is not getting passed. Styles are not applying on the HTML either. Is there something fundamentally wrong am doing with param passing to mixins?
You need to use string interpolation, i.e. replace $num with #{$num}:
#mixin wire($num) {
.parts-field {
height: 100%;
width: calc(100% * (1/#{$num}) - 10px - 1px);
}
}
The reason why this is needed because SASS will treat (...) as a calculation that has to be evaluated during compilation, and it does not know that calc(...) should be interpreted as a string and not a mathematical expression.

How can I remove the extra width to the right of jquery UI datepicker?

I am using jquery UI datepicker against a div so I can see the months on my screen. The issue is that it seems to add a width attribute that is much wider than it actually needs which creates this extra white space as seen below
here is my code:
HTML
<div id="myCalendar"></div>
Javascript:
$("#myCalendar").datepicker({
numberOfMonths: 6,
showButtonPanel: false,
beforeShowDay: function (date) {
var dateString = $.datepicker.formatDate('yy-mm-dd', date);
if ($.inArray(dateString, highlightDateArray) > -1)
{
return [true, "highlightCell", ''];
}
else
{
return [true, '', ''];
}
}
});
from looking in firebug, I see
element.style {
display: block;
width: 102em;
}
which is way longer than necessary (having it at 82em; would be fine)
What is the best way of eliminating this white space?
The issue is that it seems to add a width attribute that is much wider
than it actually needs which creates this extra white space..
Reason:
This is the way jQuery UI has been designed.
It uses a magic number 17 to calculate the width of the container.
From the code of jquery UI v1.11.4 js at line numbers 4561 thru 4574:
var origyearshtml,
numMonths = this._getNumberOfMonths(inst),
cols = numMonths[1],
width = 17,
activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
if ( activeCell.length > 0 ) {
datepicker_handleMouseover.apply( activeCell.get( 0 ) );
}
inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
if (cols > 1) {
inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
}
It checks if the number of columns (months to show) are more than 1, and calculates the width as (17 * cols) + 'em'.
Rest is taken care of by the core CSS. There are styles ui-datepicker-multi-2 thru to ui-datepicker-multi-4 which have predefined width in %. This causes the inner .ui-datepicker-group to fit within the width calculated in the Javascript code and applied in the same line (see js code above). If you see the core CSS, you will find that it is styled only for only upto 4 months across. If the number of months exceed 4, then the width is not applied to .ui-datepicker-group (although the relevant class is applied via js) and hence they do not expand to the entire width of the container.
From jQuery UI v1.11.4 css at line numbers 333 thru 341:
.ui-datepicker-multi-2 .ui-datepicker-group {
width: 50%;
}
.ui-datepicker-multi-3 .ui-datepicker-group {
width: 33.3%;
}
.ui-datepicker-multi-4 .ui-datepicker-group {
width: 25%;
}
You can see that classes for ...multi-5 and beyond are not defined.
What is the best way of eliminating this white space?
Recommended solution:
Simply add more classes as required in your custom CSS. This is the recommended way (also suggested in the response here: https://forum.jquery.com/topic/datepicket-problem-with-width-when-showing-multiple-months). And also the cleanest solution.
Just add the following lines to your custom CSS:
.ui-datepicker-multi-5 .ui-datepicker-group { width: 20%; }
.ui-datepicker-multi-6 .ui-datepicker-group { width: 16.666%; }
.ui-datepicker-multi-7 .ui-datepicker-group { width: 14.285%; }
.ui-datepicker-multi-8 .ui-datepicker-group { width: 12.5%; }
.ui-datepicker-multi-9 .ui-datepicker-group { width: 11.111%; }
.ui-datepicker-multi-10 .ui-datepicker-group { width: 10%; }
.ui-datepicker-multi-11 .ui-datepicker-group { width: 9.0909%; }
.ui-datepicker-multi-12 .ui-datepicker-group { width: 8.333%; }
This will take care of all possibilities up to 12 months across. Add more classes if required, as per your use-case.
For the sake of completeness, here is a demo:
Snippet:
$("#myCalendar").datepicker({ numberOfMonths: 5, showButtonPanel: false });
.ui-datepicker-multi-5 .ui-datepicker-group { width: 20%; }
.ui-datepicker-multi-6 .ui-datepicker-group { width: 16.666%; }
.ui-datepicker-multi-7 .ui-datepicker-group { width: 14.285%; }
.ui-datepicker-multi-8 .ui-datepicker-group { width: 12.5%; }
.ui-datepicker-multi-9 .ui-datepicker-group { width: 11.111%; }
.ui-datepicker-multi-10 .ui-datepicker-group { width: 10%; }
.ui-datepicker-multi-11 .ui-datepicker-group { width: 9.0909%; }
.ui-datepicker-multi-12 .ui-datepicker-group { width: 8.333%; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://code.jquery.com/ui/1.11.4/themes/ui-lightness/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<div id="myCalendar"></div>
And a customary Fiddle: https://jsfiddle.net/abhitalks/u07kfLaa/1/
Note: Do not attempt to change or forcibly override the core jQuery-UI CSS (unless it is absolutely unavoidable). This is not a recommended best-practice. You may end up with unexpected problems, e.g. like this artefact (shown in red circle) visible in the screenshot below, when you force the components inline-block:
And then, you will end up adding more overrides fighting that and possibly get more problems. Try to keep it clean.
It looks like a jQuery UI design oversight to me - I can't think of a reason why that extra whitespace would be intended. As you said, the widget has a fixed width in em, so this isn't just an issue of the default behavior of display: block.
In any case, we can eliminate that extra whitespace with the following steps:
Set display: inline-block and width: auto on the datepicker widget so its width shrinks to fit its contents.
To each individual calendar element, remove the float and use inline-block positioning instead (set float: none and display: inline-block).
Set white-space: nowrap on the datepicker widget. This keeps all the months on one line, preventing them from wrapping onto a second line.
We will also need to use !important on a few of these rules to get them to override the rules from the default jQuery UI stylesheet.
Here is a screenshot of what the final result looks like:
Here is a Live Demo of the code in action:
$("#myCalendar").datepicker({
numberOfMonths: 6,
showButtonPanel: false
});
.ui-datepicker {
display: inline-block !important;
width: auto !important;
white-space: nowrap;
}
.ui-datepicker-multi .ui-datepicker-group {
float: none !important;
display: inline-block;
}
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<div id="myCalendar"></div>
And a JSFiddle Version of the code: https://jsfiddle.net/cjpmyp1j/1/
As a side note, on the off-chance you were planning on setting inline styles because you are unable to include a stylesheet in your document head, look into using a scoped stylesheet in your document body alongside the jQuery UI element.

Change variable dynamically SCSS [duplicate]

Suppose I have two virtually identical HTML structures, but with different class names. They only differ by a few variables, like width and height. By using SASS/SCSS variables I thought I could do something like this:
.widget-a {
$width: 50px;
}
.widget-b {
$width: 100px;
}
.widget-a,
.widget-b {
button {
background: red;
width: $width;
}
}
This would let me write a single piece of SASS nested code for both widgets a and b. However, variables are only visible inside a nested scope, so SASS returns 'variable undefined' errors. Of course I could rewrite it by simply doing something like:
.widget-a,
.widget-b {
button {
background: red;
}
}
.widget-a {
button {
width: 50px;
}
}
.widget-b {
button {
width: 100px;
}
}
But that seems pretty cumbersome. Is there any other method of making this work?
Variables in SASS are only scoped to the block they appear in. Your first .widget-a declaration and the one declaring both A and B are two separate scopes. You'll have to do something like this (assuming you need to use the widths more than once):
$wbackground: red;
.widget-a {
$wawidth: 50px; /* widget A width */
button {
background: $wbackground;
width: $wawidth;
}
}
.widget-b {
$wbwidth: 100px; /* widget B width */
button {
background: $wbackground;
width: $wbwidth;
}
}
Ran into the same problem, this is how I'm going to try to solve it... (this works)
#mixin foo($type:"default")
.mClass
$bg: inherit
#if $type == "banana"
$bg: yellow
background: $bg
.firstClass
#include foo
.secondClass
#include foo("banana")
Your problem can be solved by using a mixin.
#mixin button($width){
button{
background:red;
width:$width;
}
}
.widget-a{ #include button(50px); }
.widget-b{ #include button(100px); }
I don't see the advantage of creating a mixin only for this specific situation, it is hardly useful on a couple of occasions, but it is just my opinion.
Anyway, I've created a mixin, just for fun. I think that it can help you to deal with this specific situation. Here is the mixin and I'm going to try to explain how it works:
#include button($selectors, $property, $values, $child: false) {
// Common properties that are included in all $selectors
}
This mixin takes four parameters:
$selectors: List of selectors, in your case, .widget-a and .widget-b, they should be enclosed in quotes.
$property: Here you should enter the name of the property, in your case width
$values: Values ​​are, as the name implies , the values of the property for each selector
$child: Here you can enter the name of a child, this is optional.
Into the brackets {} you should write all the properties that you want to include in all $parameters
The order of each selector must match the order of their corresponding value
So, here's an example using this mixin to solve your problem. This is the #include:
#include (".widget-a" ".widget-b", width, 50px 100px, button) {
background: red;
}
And this, the code that returns:
.widget-a button, .widget-b button {
background: red; }
.widget-a button {
width: 50px; }
.widget-b button {
width: 100px; }
This is another way to achieve the same result:
#include button(".widget-a .button" ".widget-b .button", width, 50px 100px) {
background: red;
}
Download the mixin here

use width inside of calc

I am trying to do something like this:
.my-style {
width: 50px;
margin-left: calc(50% - calc(width / 2));
}
Later I am changing the width to 90px and I want the margin grow accordingly.
It doesn't work. Is it possible?
The newest browser's SHOULD support it, I tried the following code.
This is a webkit example I made, so check it in chrome
CSS
p {
-webkit-var-a: -webkit-calc(1px + 3px);
margin-left:-webkit-calc(-webkit-var(a) + 5px);
}
HTML
<p>This text should have margin-left, but it doesn't</p>
FIDDLE
http://jsfiddle.net/uqE8b/
If you inspect the <p> element you can see that it DOES see the code as valid, it just doesn't do anything... So it seems that for now you have to use javascript, LESS or anything equivelent as it's still a experimental feature.
EDIT:
it DOES seem to work when you make the var a plain number:
p {
-webkit-var-a: 3px;
margin-left:-webkit-calc(-webkit-var(a) + 5px);
}
http://jsfiddle.net/uqE8b/1/
So to answer your question, yes this is possible, but I would not recommend it for now.
CSS
.my-style {
height:100px;
background-color:black;
-webkit-var-width: 50px;
margin-left: -webkit-calc(50% - -webkit-var(width) / 2);
}
FIDDLE
http://jsfiddle.net/ShsmX/
You can't do something like that with standard CSS, you should investigate an alternative such as LESS
Edit: I was wrong, CSS3 supports this if you use var() within calc():
.my-style {
width: 50px;
margin-left: calc(50% - (var(width) / 2));
}
I think should do it.
.my-style {
width: 50px;
margin-left: calc(100% - calc(width / 2));
}
Try like this, it worked wonder for me.