Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: support percentages for width and height #412

Closed
tjvantoll opened this issue Jul 8, 2015 · 46 comments
Closed

Feature request: support percentages for width and height #412

tjvantoll opened this issue Jul 8, 2015 · 46 comments
Assignees
Milestone

Comments

@tjvantoll
Copy link
Contributor

@tjvantoll tjvantoll commented Jul 8, 2015

My use case is wanting layout items to take up a certain portion of the screen across screen resolutions. For example suppose I'm building this UI:

I want to say that the <TextBox> and <Button>s are width: 80% (or that their parent <StackLayout>) is, but currently I have to pick an arbitrary numeric amount.

I can get the behavior I seek if I create elements in JS, by getting the screen width and using that to derive percentage-based widths, but that's a lot of work. I'd love to be able to type %, in CSS as well as layouts—especially <GridLayout>.

@bsatrom

This comment has been minimized.

Copy link

@bsatrom bsatrom commented Jul 8, 2015

+1.

After all, life is about percentages. There are few absolutes...

@alejonext

This comment has been minimized.

Copy link

@alejonext alejonext commented Jul 8, 2015

+1 a grid

@atanasovg

This comment has been minimized.

Copy link
Member

@atanasovg atanasovg commented Jul 9, 2015

@tjvantoll This is a good feedback and I think there shouldn't be any technical challenges to implement it. @hshristov What do you think?

Otherwise you may achieve the scenario (or at least a close version) by using different approach - you may have the horizontal/vertical alignments set to stretch and use the margin property to define some spacing from the screen edges.

@emiloberg

This comment has been minimized.

Copy link

@emiloberg emiloberg commented Jul 9, 2015

As I wrote in the CSS properties issue this is an important part to create good ui. Big 👍

@hshristov

This comment has been minimized.

Copy link
Member

@hshristov hshristov commented Jul 10, 2015

@tjvantoll Wouldn't margin do the same thing (as @atanasovg) suggested? Also all Layout subclasses have padding property which allows you to move all children instead of adding margin to all of them.

As for the % width/height I will have to spike it to see what type of problems will arise. It should takes percent of the width/height its parent gives it when measured, right? So it is not really single calculation but instead depends on the available size.

@tjvantoll

This comment has been minimized.

Copy link
Contributor Author

@tjvantoll tjvantoll commented Jul 10, 2015

Hey @hshristov,

The problem with margin is that I still have to hardcode a numeric value, which doesn't let me get accurate proportions across devices. In the login form above say I want that <TextField> to have a width of 80%. On a 320-“pixel”-wide device I can set Margin: 32 and be all set. But if I open that same code on my iPad the <TextField> is going to take up a lot more than 80% of the screen.

It should takes percent of the width/height its parent gives it when measured, right? So it is not really single calculation but instead depends on the available size.

Correct. If the parent has a width 320, and I add TextField { width: 80%; }, I'd expect the <TextField> to have a width of 256.

@valentinstoychev

This comment has been minimized.

Copy link

@valentinstoychev valentinstoychev commented Jul 13, 2015

Hey - @tjvantoll - I know you are web ninja - how would you do this in web page? Would bootstrap or flexbox help you?

@tjvantoll

This comment has been minimized.

Copy link
Contributor Author

@tjvantoll tjvantoll commented Jul 13, 2015

For this layout I'd toss width: 80% on a container element, and make everything within the container width: 100%. For example: http://jsbin.com/qihoqanogu/1/edit?html,css,output.

Flexbox tends to be a bit clunky for really simple scenarios, but invaluable for more advanced layouts—especially in a responsive design context, as it lets you change the layout based on screen size elegantly.

Bootstrap's grid system, or Foundation's, or one of the many other that exist, are very commonly used for layout in the web world. I'm personally not a fan as I find the abstraction just adds complexity; I'd rather hand code the CSS.

@bfattori

This comment has been minimized.

Copy link

@bfattori bfattori commented Jul 13, 2015

+1

The only issue is that the element with the absolute size shouldn't be too far up the visual display tree. I feel like it might slow down the layout process to a crawl if everything were relative via percentages. So, rather than trying to mimic the browser where it crawls up the DOM tree looking for the first positionable parent, instead require that the parent has a fixed size. Or, if that's not reasonable, implement the sizing code natively.

I'd hate to see the mess that is static vs relative/absolute when one of the parents doesn't have a defined size and it has to skip around trying to find one until it lands on the body element.

@valentinstoychev

This comment has been minimized.

Copy link

@valentinstoychev valentinstoychev commented Jul 14, 2015

Thanks @bfattori and @tjvantoll . We will incorporate this feedback into the research with the spike. The performance notes are definitely very important and we will make sure to measure the overhead.

@emiloberg

This comment has been minimized.

Copy link

@emiloberg emiloberg commented Aug 27, 2015

Is there an update on this issue? I totally agree with the 'S:High' label.

@hshristov

This comment has been minimized.

Copy link
Member

@hshristov hshristov commented Sep 8, 2015

Hi all,

I've spiked simple % based layout and I have few cases in which I don't know what is the expected result.
For example in this scenario:

<StackLayout orientation="vertica">
   <Button text="button 1" horizontalAlignment="left" width="50%" height="50%" />
   <Button text="button 2" horizontalAlignment="stretch" width="50%" height="50%" />
   <Button text="button 3" />
</StackLayout>

So in this case questions are:

  • Should first button get half of the available size, second - 1/4, third - the remaining? Or should first two buttons both equal of the available height and no space for third one?
  • Should first button width be 50% from the available width no matter that its alignment is left or should it work only if alignment is stretch (like the second button)
  • More generally when width is set the element is measured/layouted with this width. So should widthPercent be treated the same way? If so there won't be height for the third button.

Edit:
I've checked Android support library and they have chosen the option where width\height percents are based on the parent size and they apply these values on ViewGroup children (before children are measured) so it appears like children have explicit width/height set. This is easier to implement but I'm not sure it will cover all scenarios. In their case the third button won't be shown too.

Please share your feedback.

@emiloberg

This comment has been minimized.

Copy link

@emiloberg emiloberg commented Sep 8, 2015

My 2 cents:

  • Should first button get half of the available size, second - 1/4, third - the remaining? Or should first two buttons both equal of the available height and no space for third one?

I'd treat this as faulty code. Button 1 and 2 should be 50% leaving no space for Button 3. However

   <Button text="button 1" horizontalAlignment="left" width="10%" height="50%" />
   <Button text="button 2" horizontalAlignment="stretch" width="20%" height="50%" />
   <Button text="button 3" />

should leave 70 % for button 3.

  • Should first button width be 50% from the available width no matter that its alignment is left or should it work only if alignment is stretch (like the second button)

A width declaration should take precedence

  • More generally when width is set the element is measured/layouted with this width. So should widthPercent be treated the same way? If so there won't be height for the third button.

Not really following this question.

@hshristov

This comment has been minimized.

Copy link
Member

@hshristov hshristov commented Sep 8, 2015

@emiloberg
should leave 70 % for button 3.
You mean that it should leave 70% of the width which is given to the StackLayout and stackLayout is horizontal, right?

Not really following this question.
I was wondering should widthPercent actually change width of the element before it is measured so that it gets exactly the size based on parent measure size or should it be based on the remaining space like in the above example first button will get - 1/2 of the available height, then second one will get 1/4.

@jlooper

This comment has been minimized.

Copy link

@jlooper jlooper commented Sep 8, 2015

I would have hoped for a way to layout a grid with percentages, something like:

<GridLayout columns="50%,50%" rows="auto, *" >

and then we can have the items within the grid columns either stretch, have a percentage width within its parent, or have an absolute value. Is this the direction you're going? Maybe this is just a sneaky request for Flexbox ...

@hshristov

This comment has been minimized.

Copy link
Member

@hshristov hshristov commented Sep 8, 2015

I saw the missing GridLayout :) (nice github feature to drop everything in < >)
Well actually I was thinking about percent support only for width, height, marginLeft, marginRight, marginTop and marginBottom. No other properties but I guess if this is needed I can research it.
btw:

<GridLayout columns="*, *" />

will give you the same as columns="50%,50%". Is there something I'm missing?
As for the Flexbox I'm searching for use-cases :)

@jlooper

This comment has been minimized.

Copy link

@jlooper jlooper commented Sep 8, 2015

@hhristov bad example on my part. What about when you have to have uneven widths, like 20%,60%,20%?

@hshristov

This comment has been minimized.

Copy link
Member

@hshristov hshristov commented Sep 8, 2015

@jlooper - same as ** columns="1_, 3_, 1_" *_.
When there is * (star) column the grid takes all the available width that remains after fixed and auto columns are measured. If there are more star columns the space is distributed based on the star count. That means that 3* column will get three times the width of 1* column.

What bugs me in the flexbox layout is that it is supposed to be used without changing the html. I'm by no means html, css expert - quite the opposite so please correct me if I'm wrong. You just mark one element as flexbox container and that's it. But in the native platforms (like Android and WU) elements cannot be added everywhere. Only ViewGroup (in Android) can have children.

So it will not be possible to specify the layout using only CSS. One should have something like FlexboxLayout element somewhere in the XML.

Doesn't this defeat the purpose of flexbox?

@emiloberg

This comment has been minimized.

Copy link

@emiloberg emiloberg commented Sep 8, 2015

You mean that it should leave 70% of the width which is given to the StackLayout and stackLayout is horizontal, right?

Right

I was wondering should widthPercent actually change width of the element before it is measured so that it gets exactly the size based on parent measure size or should it be based on the remaining space like in the above example first button will get - 1/2 of the available height, then second one will get 1/4

I'm unsure if I'm answering the question but:
Imho: both height and width should change the size of the element based on the parent measured size. Eg. an element with width 100% should take the full width of the parent element.

Example:

<StackLayout orientation="horizontal">
    <StackLayout orientation="horizontal" width="80%">
       <Button text="button 1" width="50%" />
       <Button text="button 2" width="50%" />
    </StackLayout>
    <StackLayout orientation="horizontal" width="20%">
       <Button text="button 3" width="100%" />
    </StackLayout>
</StackLayout>

Button 1 here takes 40 % of the screen width, so does button 2. Whereas button 3 takes 20% of the full screen width.

Could you clarify "same as ** columns="1, 3, 1" *."?

@jlooper

This comment has been minimized.

Copy link

@jlooper jlooper commented Sep 8, 2015

Same as @emiloberg, I need clarification, please... I've seen this syntax before: columns="1, 3, 1*" or something similar (is that right?), and after thinking about it a bit, I see how it would make sense that 1,3,1 would translate to 20%,60%,20%. I would just have to get used to it. Normally when I see a number in the columns I'm assuming it's a pixel number, not a percentage, like in the docs. Is this other syntax documented?

@ligaz

This comment has been minimized.

Copy link
Contributor

@ligaz ligaz commented Sep 8, 2015

The magic happens in this code. The star notation comes from our XAML background and is described here as "weighted proportion of available space". In the CSS Grid Layout Module Working Draft spec it is referred as flexible length.

Here are some examples:

  • "2*, *" - means two columns (or rows) the first one taking ⅔ of the space and the second one ⅓.
  • "*, 3*, *" - 3 columns (rows), first taking 20%, second 60% and third 20% of the space.

We might want to align our naming and definition more closely to the CSS Grid Layout specification but I will let @hshristov comment on this 😄

@tjvantoll

This comment has been minimized.

Copy link
Contributor Author

@tjvantoll tjvantoll commented Sep 8, 2015

Woah, this thread is getting a bit epic. I'll chime in with a few replies to @hshristov:

<GridLayout columns="*, *" />
will give you the same as columns="50%,50%". Is there something I'm missing?

The problem is this syntax is very confusing to people with zero XAML experience (aka me, @jlooper, etc), as CSS has no concept of this syntax currently. I love the idea with aligning our conventions with the CSS grid layout spec moving forward.

What bugs me in the flexbox layout is that it is supposed to be used without changing the html. I'm by no means html, css expert - quite the opposite so please correct me if I'm wrong. You just mark one element as flexbox container and that's it. But in the native platforms (like Android and WU) elements cannot be added everywhere. Only ViewGroup (in Android) can have children.

So it will not be possible to specify the layout using only CSS. One should have something like FlexboxLayout element somewhere in the XML.

The advantage of flexbox is not that you have one less element in your visual tree, because in HTML you'll basically always have a <div> that acts as your flex container. The advantage is that you can control everything about your layout in CSS rather than your markup. The idea is that using flexbox keeps your markup clean, as layout “things” (height, width, orientation, etc) stay in CSS and not HTML. This is especially useful when you need to handle multiple screen sizes. For instance, if you want to layout elements differently on phones and tablets, you don't need to change your markup—all you need to do is add a media query. That same use case is really hard to accomplish in NativeScript today.

Anyways I think the argument for and against adding flexbox to NativeScript is outside the scope of this issue. Although I'm pro-flexbox because I come from a web development background, I have some big concerns about maintaining and documenting two different layout mechanisms.

For now, having syntax like columns="50%,50%" would my web developer brain happy, even if it's functionally equivalent to columns="*, *".

@emiloberg

This comment has been minimized.

Copy link

@emiloberg emiloberg commented Sep 8, 2015

For now, having syntax like columns="50%,50%" would my web developer brain happy, even if it's functionally equivalent to columns="*, *".

👍

@hshristov

This comment has been minimized.

Copy link
Member

@hshristov hshristov commented Sep 8, 2015

@jlooper sorry but this markup continue to mess up my posts ;)
I meant

columns="1*, 3*, 1*" 

not "1, 3, 1". As you correctly pointed when there is no star - it is fixed column.

@ligaz I've checked Grid specification before we did our layout and I think we can align both but in CSS. Right now setting GridLayout options (rows/columns) is not allowed in CSS and if we allow it we will use the same CSS names. Does this sounds good?
As for the star issue - I guess it is not so known but the Grid CSS specification defines 'fr' which is as meaningful as star :)

@tjvantoll that is the point - to bring up discussion :)
For columns="50%, 30%" it could be done but only after we make percent based layout. The point is both columns sums up to 80% of the available size so in the end we need % layouts if we are going to support this case.
As for the flexbox layout - I'm not against it. On the contrary. I want to see as much cases as possible before we commit of doing it. I understand its advantages but like I said I don't see how it will fit in our XML.

For example in HTML you place div somewhere, name it and then specify its flexbox parameters in the CSS. But in our XML you don't have 'div'. Only elements that inherits from LayoutBase support adding views. So I want to see some possible code (xml & css) on how do you image it.

The way I see it - you will have few 'FlexboxLayout' tags in the XML and the in CSS you will specify their options as well as children options.

<Page>
    <FlexboxLayout id='rootContainer'>
        <Button id='element1' />
        <Button id='element2' />
        <FlexboxLayout id='innerContainer'>
            <SomeMoreControlsHere id='element3'/>
        </FlexboxLayout>
    </FlexboxLayout>
</Page>

When more complex layout is needed developer will have to nest more FlexboxLayout containers which goes against Google performance recommendation - to use as flat structure as possible.
That is why we have our GridLayout in the first place. It support fixed, auto and star (proportional) columns/rows. With it you can create complex layouts and even simulate all other layouts (not so convenient but still possible). With the addition of percent width, height, margins it will give even more flexibility.

But that's just my vision. Does it looks OK?
Do you have something different in mind?

Please comment on this and on percent based layout.

@hshristov

This comment has been minimized.

Copy link
Member

@hshristov hshristov commented Sep 8, 2015

@emiloberg Yep you understand it correctly. I think @ligaz explained '1,3,1' part better than me.

@tjvantoll

This comment has been minimized.

Copy link
Contributor Author

@tjvantoll tjvantoll commented Sep 9, 2015

For columns="50%, 30%" it could be done but only after we make percent based layout. The point is both columns sums up to 80% of the available size so in the end we need % layouts if we are going to support this case.

I'm definitely in favor of supporting %-based layouts. It's why I created this issue in the first place :)

I'll comment on flexbox too, but I worry that we're getting off topic from the main %-based layout discussion. For flexbox most of the good use cases can already be implemented in NativeScript. For instance flexbox is the de facto solution for vertical centering on the web, but NativeScript uses vertical-align in a way the web doesn't. Flexbox is also how I tend to structure my top-level layouts, but in NativeScript I'd use a <GridLayout> to handle that.

A <FlexboxLayout> might be nice, but mainly because it's familiar to web developers, and not necessarily because it solves use cases that the current NativeScript layouts don't. Thinking about this more, I'd say what I'd really like to see in NativeScript is the ability to control everything about a layout in CSS.

I'll give an example. Suppose I have a sidebar that I want to show on tablets and hide on small devices. On the web with flexbox and media queries this is trivial (see http://jsfiddle.net/tj_vantoll/xg2ujdsg/), but in today's NativeScript the implementation would be crazy hard. Even if we supported media queries, I'd still have to create multiple XML files because I can't change orientation, rows, or columns in CSS.

There are other uses cases that aren't tied to screen sizes too. Imagine I have two states in my app, and I have some way to toggle between them. In NativeScript if I wanted to dynamically change rows or columns I'd have to do it with some messy JavaScript. On the web I'd just toggle a CSS class name on some arbitrary element and then handle everything in CSS.

@ligaz

This comment has been minimized.

Copy link
Contributor

@ligaz ligaz commented Sep 10, 2015

There is one issue I see if we go down the percentage road. What should be the expected outcome of the following definition: 50, 50%, 50%?

In the star world this means that the second and the third things will get 50/50 of the available space after the first things occupies 50 pixels of it. In the web world isn't those 50% be calculated based on the whole available space and not the one that is left after all other elements are measured?

@hshristov hshristov modified the milestones: 1.6 (Under Review), 1.5 Nov 23, 2015
@atanasovg atanasovg modified the milestones: 1.5.1, 1.5.1 (Under Review) Nov 26, 2015
@amjd

This comment has been minimized.

Copy link

@amjd amjd commented Dec 1, 2015

+1. Really need this.

@mike-ense

This comment has been minimized.

Copy link

@mike-ense mike-ense commented Jan 13, 2016

When will we see some % functionality usable,

Is anything fairly testable today or in a week etc.?

Just a thought, CSS misses combinations e.g. 5% + 0.5em + 2px.

Also a % value may be relative to more than one thing, so that topic needs some care.

Just touched on this with NativeScript/docs#218 , as @vakrilov just mentioned.

@dragGH102

This comment has been minimized.

Copy link

@dragGH102 dragGH102 commented Jan 14, 2016

+1 for % support

@NathanaelA

This comment has been minimized.

Copy link
Contributor

@NathanaelA NathanaelA commented Jan 20, 2016

@vchimev, Vasil, you marked this as Done, is their an actual pull request for this somewhere?

@NathanaelA

This comment has been minimized.

Copy link
Contributor

@NathanaelA NathanaelA commented Jan 20, 2016

Ok, I found then #1257 and #1348.

@asiby

This comment has been minimized.

Copy link

@asiby asiby commented Nov 14, 2016

Hi guys. I am new to {N} but not to mobile app development. I am thinking of something that may help anyone who to give this a try because I am not 100% comfy with plugin development yet.

What if you apply layout constraints that can actually act as max-width, max-height, min-width or min-height. Those do exist in both do have the equivalent of those.

Thoughts anyone?

@34r7h

This comment has been minimized.

Copy link

@34r7h 34r7h commented Dec 1, 2017

+1 for relative units!!

@lock

This comment has been minimized.

Copy link

@lock lock bot commented Aug 27, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked and limited conversation to collaborators Aug 27, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
You can’t perform that action at this time.