In CSS there is padding and margin, the former adds empty spaces inside border, and the latter adds spaces outside. Currently I am learning SwiftUI, and I found the .padding modifier, which is equivalent to CSS's padding property, but cannot find margin's correspondence.
Does it exist or am I to create a wrapper view to achieve this goal?
SwiftUI's layout modifiers can be a bit confusing if you're coming from HTML and CSS.
Where CSS has a huge list of properties to choose from, SwiftUI tries to keep things simpler. To do that, it takes advantage of the ability to "chain" modifiers together.
For example, if you had a rectangle that needs internal padding of 8 pixels, a border of 1 pixel width and external margins of 10 pixels, you might express it in CSS like this:
.my-rectangle {
padding: 8px;
margin: 10px;
border: 1px solid red;
}
And in CSS it doesn't matter what order those properties occur within the double braces; each has a specific meaning and is applied in the same way, even if the border property is at the end or the beginning.
In SwiftUI, though, styling is done by applying a modifier to a View, giving you a new view with the modification applied. You can then apply another modifier to that, and another, and so on. And because each modifier is adapting what has gone before, the order is very important.
So if we have a view to which we need to add the same spacing as the example above, we'd structure it something like:
MyView()
.padding(8) // <-- internal padding
.border(Color.red, width: 1) <<-- apply the border
.padding(10) // <-- apply more padding outside the border
Building views up gradually like this is what allows SwiftUI to keep the number of modifiers you need for most views reasonably small and focussed.
As you start building up more complicated views, you'll come across stacks and grids, which also have a concept of spacing between children. Depending on your design, it might be more useful to think about using spacing instead of external padding, especially if you start breaking your design up into reusable components.
But thinking about applying changes in a sequence, instead of all at once like CSS, is the key to constructing great SwiftUI views.
Related
I want to section off one area of a layout from another visually in my Vaadin Flow layout using the Java API.
I want something like the hr horizontal rule found in HTML. I would also want the equivalent, a vertical rule (which was never defined in HTML).
Is there some easy way to have a visual indicator of a thematic shift between parts of a layout?
Hr class
For an <hr> there is the Hr class.
verticalLayout.add(new Span("First"), new Hr(), new Span("Second"));
Roll-your-own
Another option is to create classes for the dividers, there are a few different ways of doing this, here's an example
public class Divider extends Span {
public Divider() {
getStyle().set("background-color", "blue");
getStyle().set("flex", "0 0 2px");
getStyle().set("align-self", "stretch");
}
}
And used as such
horizontalLayout.add(new Span("First"), new Divider(), new Span("Second"));
Using align-self and flex will only work in flex layouts, which includes HorizontalLayout and VerticalLayout. The beauty of this approach is that the same class will work in both. The flex: 0 0 2px tells it to be 2 pixels wide in the direction of the container, and not grow or shrink. The align-self: stretch will tell it to take the full size of the container in the perpendicular direction.
I write this answer as follow-up to my comment on Tazavoo's answer, which is great! I love their custom Divider class, and it has been asked whether this divider can be customized/styled further, something like it is done in this gradient borders page.
Of course this divider can be styled further! But the difference between the divider and the elements in the link is that in the link, the borders of an element is styled, while we need to style the actual element itself here.
CSS attribute in the linked page: border-image. CSS attribute for the Divider background-image.
(I am not familiar enough with CSS -webkit attrributes, so I don't know if you need more than just background-image for a good visualisation in all browsers)
The linked page makes the linear-gradient go in the direction to bottom. We could use that too, but then using the Divider horizontally would look different than using it vertically. That is why we need to set the direction to a diagonal, so both usages of the divider have a similar gradient. See proof of concept in w3schools' TryIt Editor
Here is how I set up the Divider class with a gradient:
public class Divider extends Span {
public Divider(){
getStyle().set("background-image", "linear-gradient(135deg, #777 , rgba(0, 0, 0, 0))");
getStyle().set("flex", "0 0 2px");
getStyle().set("align-self", "stretch");
}
}
To customize the linear gradient even more, please see the docs on w3schools
All the credits of the divider class go to #Tazavoo. Please go upvote their answer
I have a CheckBoxGroup that shows 8 items. The default presentation is vertical, which does not really look good in my layout.
But if I set the presentation to horizontal using
checkBoxGroup.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL);
then the 8 items do not have enough space. So I am forced to use the vertical style but I am not at all content with that.
Is there a way to show a single CheckBoxGroup horizontally, but using 2 (or more) rows?
Edit:
I have found a quick-fix to the problem by styling the checkboxes to be floating to the left (with horizontal presentation of the group). It now shows 6 Checkboxes on the first line, and 2 on the second line. It is still not beatiful, but better than the other 2 options. I am still looking forward to receiving a better solution! (if there is none, then so be it but at least I then know that it is not possible)
This should be doable with flex box, since CheckBoxOptions are spans in div. So we need to add flex css rules for the checkBoxGroup.
First add stylename
checkBoxGroup.addStyleName("my-flex-checkboxgroup")
Then in your theme
.my-flex-checkboxgroup {
display: flex;
flex-wrap: wrap;
width: XXXpx
height: auto;
}
You need to set the width XXX so that four columns fit
E.g. if you have
CheckBoxGroup checkBoxGroup = new CheckBoxGroup();
checkBoxGroup.setItems("Option 1","Option 2","Option 3","Option 4","Option 5","Option 6","Option 7","Option 8");
You need rougly 500px or so, but if captions are longer, more naturally.
This worked for me atleast.
If I add too many/too long captions to a vaadin7 timeline, they will only be displayed partially (i.e. the part we have space for is displayed and the remainder is truncated)
How can I increase this area in order to allocate enough space for all?
timeline.setGraphCaption(container, h.toString());
You need to add these rules in your scss file:
.v-timeline-widget .v-timeline-widget-modelegend{
background: inherit;
}
.v-timeline-widget-legend-label{
height: auto !important;
white-space: normal !important;
}
Before:
After
3 points:
While these rules may not met criteria of well-written CSS or good practice rules (I am looking at you !important), they do the trick. Still, better approach would be to get your hand dirty by editing Vaadin Timeline addon sources.
As you surely noticed text background has changed. That's because we override default background which was designed for only one line (you should provide your own background image)
Bottom of the widget is cut off by few pixels. Well, the only way to fix it is to jump into DOM and css and try fix it. Doable but I haven't tried.
This is a very basic CSS design question.
When I have two block-elements
+----------+ +----------+
|~~~~~~~~~~| |**********|
|~~~~~~~~~~| |**********|
|~~~~~~~~~~| |**********|
+----------+ +----------+
and I want to set the space between them, there are three possibilities:
Left block with right margin
Right block with left margin
Margin for both blocks
What are the pros and cons for each one and—most importantly—what is considered
best practice?
It is generally a good idea to choose a direction (margin-left OR margin-right) and to stick to it on the whole project so designing will be easier and more consistent.
For more on the subject you can read this blog post: Single-direction margin declarations
That said, margin-left on boxes means "I do not want to be too close to the box before me" while margin-right means "I do not want other boxes to be too close to me".
So on designs where boxes have a margin by default, use margin-right (and margin-bottom) and on designs where boxes have no margin by default, use margin-left (and margin-top) on the few boxes with a margin. If it is mixed, choose the direction that seems the most coherent to you and stick to it.
No pros and cons, it is totally on your design, what you want to go for, using margin-right will make the last element have margin-right for no good reason, so say for example, you have three boxes, floated to the left, or they are displayed inline-block so because of the right margin, the last box won't touch the extreme right of the template, instead it will wrap and move down.
Do you see the red space, it's margin-right for the last element, which you won't need. shifting it more will result your div to move down.
Solution?
If you are willing to support legacy browsers, assign a class to the last element and write margin-right: 0;, say you are having 3 li elements floated, so you will write
ul.class_name li.class_name {
margin-right: 0;
}
Else, you can use :last-child pseudo to get rid of the extra margin.
So it will be
ul.class_name li:last-child {
margin-right: 0;
}
Same thing will go for the left, but instead of using :last-child and margin-right you need to use margin-left and :first-child respectively.
Last but not the least, using margin on both sides, will create a space on both the sides, again, resulting in disorientation of your layout.
In the above case, you will have to use both, either assign class to first and last element, or you need to use :first-child and :last-child to get rid of margin on the left for first element and margin on the right for last element.
Conclusion: For the two boxes you have, you should use margin-right
and use a class or :last-child to remove the extra margin on the
last element.
It depends where you will use it and how you will use it there is no exact rule for this. However if you will use some grid system for elements it is best practice. If your element cannot be suitable for grid system you can use any approach.
P.S. And there is another possibility to use pseudo element after or before I guess.
Simple Answer: It depends
It all depends on what you are trying to do, and what elements are those.
For example, if your site is oriented to the left, and those are two floating divs, with the same class, you wouldn't want to use margin-left, because that will introduce some space on the left of the first block.
It obviously makes no sense to add margin to both elements, unless you have dynamic content that may appear in between.
So, other than the obvious styling manner that you want your page to have, there is no difference in performance, but mostly readability of your code
I would like to know the exact size of an element without margin, border and padding, just the width and height of the most inner box (see image below).
Currently i'm aware of the function "getBoundingClientRect" which gives the size including border and padding. There is also the "client" property which returns a Rect including the padding.
So the question is, how do i get the width and height without padding?
Unfortunately the DOM does not provide such functionality. That's why most libraries like jQuery, ExtJS, etc. provide helper methods. They essentially parse the style and figure it out.
Here's an example:
<div style="width: 100px; height: 100px; padding: 5px; border: 1px solid #000"></div>
int getWidth(Element element) {
var paddingLeft = element.style.paddingLeft.replaceAll('px', ''); // You may want to deal with different units.
var paddingRight = element.style.paddingLeft.replaceAll('px', '');
return element.clientWidth - int.parse(paddingLeft) - int.parse(paddingRight);
}
And the usage:
print(getWidth(query('#test')));
Result:
100
Notes:
You might consider dealing with different types of units (px, pt, em, ...).
The box-sizing property also has an effect you might want to check for.
If I or you happen to find the time, perhaps release a Pub package or something. :)
This pub package can predict the size of a text (without margin, border and padding) that does not yet exist in the DOM: https://pub.dartlang.org/packages/textent
Try the relatively recently introduced Element.contentEdge, that seems to be exactly what you want.
This comment from a Google employee lists some more related methods that has also been added. Note that at least some of them are still marked as Experimental in the API docs, but they can be useful nonetheless.