safe-area icon indicating copy to clipboard operation
safe-area copied to clipboard

Safety margins value getter

Open dirkcremers opened this issue 1 year ago • 20 comments

First of all, thanks for maintaining the plugin. It's really helpful, and I appreciate your effort.

Is your feature request related to a problem? Please describe. After integrating the plugin and configuring settings in capacitor.config.ts, our application achieved an edge-to-edge display, which is fantastic. However, we're encountering issues with content overlapping with the device notch, for instance. We're exploring options to maintain edge-to-edge layout while ensuring content remains within safety margins.

Describe the solution you'd like We're looking for a getter function that can provide the safety margin values for different devices.

Describe alternatives you've considered

Additional context As I'm new to Capacitor, I'm still familiarizing myself with its framework. However, I'm eager to learn and contribute to the project in case I can.

dirkcremers avatar May 16 '24 18:05 dirkcremers

There is a different plugin that does this: https://www.npmjs.com/package/capacitor-plugin-safe-area

I've never used it though, so no recommendation, just information.

frederikheld avatar May 17 '24 00:05 frederikheld

Could you provide me with some info as why you would want a getter function? This plugin injects a CSS variable which you can use directly in your CSS. For example, it enables you to do the following:

#header {
  padding-top: var(--safe-area-inset-top);
}

Maybe it's not very clear from the docs that this is the case. So I will update the docs accordingly. Please let me know if this 'fixes' your issue

tafelnl avatar May 17 '24 08:05 tafelnl

@frederikheld Thank you for the information. If you'd like to know the differences between that plugin and this one, I've outlined them here: https://github.com/AlwaysLoveme/capacitor-plugin-safe-area/issues/29

tafelnl avatar May 17 '24 08:05 tafelnl

I think the docs are a bit easier to understand with this change: #11

Let me know what you think and if your issue is resolved now

tafelnl avatar May 17 '24 08:05 tafelnl

Thank you for the hint about the injected css variable. A JavaScript getter would still be useful.

Use Case:

I have a map that covers the top half of the screen and goes right to the edge. So there is an unsafe part that the user can't interact with and that will be overlaid with status bar text and icons. The map is centered to a location and I want the centering to compensate for the unsafe area.

frederikheld avatar May 17 '24 10:05 frederikheld

Could you provide me with some info as why you would want a getter function? This plugin injects a CSS variable which you can use directly in your CSS. For example, it enables you to do the following:

#header {
  padding-top: var(--safe-area-inset-top);
}

Maybe it's not very clear from the docs that this is the case. So I will update the docs accordingly. Please let me know if this 'fixes' your issue

A question about this: did I understand the whole safe area CSS stuff correctly that env(safe-area-inset-*) only exists on iOS, but your solution var(--safe-area-inset-top) works on all platforms?

frederikheld avatar May 17 '24 11:05 frederikheld

env(safe-area-inset-*) exists on all platforms (https://developer.mozilla.org/en-US/docs/Web/CSS/env#browser_compatibility). But there's a bug on Android that it doesn't provide the correct values (it will always be 0px) when trying to use it in a webview with Edge-to-Edge enabled

With this plugin var(--safe-area-inset-*) will also exist for all platforms. For all platforms except Android it will just have the exact same value as env(safe-area-inset-*)

tafelnl avatar May 17 '24 11:05 tafelnl

Ah, okay. Thanks a lot for the clarification!

frederikheld avatar May 17 '24 11:05 frederikheld

As for your other question, I'm not sure I'm willing to accommodate for that type of behavior in this plugin, for several reasons:

  • I want to keep this plugin as simple as possible
  • It's another feature to maintain
  • Most importantly, it's already possible in plain JavaScript: https://stackoverflow.com/a/68526312/8634342

tafelnl avatar May 17 '24 11:05 tafelnl

I understand. But reading computed styles only works in some cases. If the plugin knows those values before the CSS is rendered, it would help if we could access them directly through JS.

frederikheld avatar May 17 '24 11:05 frederikheld

If the plugin knows those values before the CSS is rendered, it would help if we could access them directly through JS.

Using a new MutationObserver instead of a SafeArea.addListener('safeAreaChanged') for example, is just as fast. They both have to wait till the JavaScript has been loaded.

But reading computed styles only works in some cases.

I'm not sure what you mean by this

tafelnl avatar May 17 '24 11:05 tafelnl

I have a map that covers the top half of the screen and goes right to the edge. So there is an unsafe part that the user can't interact with and that will be overlaid with status bar text and icons. The map is centered to a location and I want the centering to compensate for the unsafe area.

How is this not already possible using CSS by the way?

tafelnl avatar May 17 '24 11:05 tafelnl

If the plugin knows those values before the CSS is rendered, it would help if we could access them directly through JS.

Using a new MutationObserver instead of a SafeArea.addListener('safeAreaChanged') for example, is just as fast. They both have to wait till the JavaScript has been loaded.

But reading computed styles only works in some cases.

I'm not sure what you mean by this

computed style means: the CSS values that the browser has computed after applying all CSS directives. The browser computes those values during rendering. So they will only be available AFTER rendering. But in some cases they are needed before rendering because otherwise you have to update an element that has already been rendered which can cause layout shifts.

This is a common issue when you use getComputedStyle to read the hight of an element with dynamic height because the height will only be known after the element has been rendered and display and position attributes have been applied.

I expect the same issue here.

frederikheld avatar May 17 '24 11:05 frederikheld

I have a map that covers the top half of the screen and goes right to the edge. So there is an unsafe part that the user can't interact with and that will be overlaid with status bar text and icons. The map is centered to a location and I want the centering to compensate for the unsafe area.

How is this not already possible using CSS by the way?

Because the Google Maps JS SDK is a very well designed modern library with great DX /s

IDK, ask the Google guys. But you do the centering via JS. Of course I could move the whole map via CSS, but then I don't have the e2e look anymore. I just want to move the center to have the map centered within the safe area.

// EDIT: Maybe it's not clear what I mean by "centering" if you are not familiar with maps: with the Google Maps SDK you can embed an interactive map into your app. And you can define which Geolocation will be centered in the visible area of the map via JS. With the notch, I have a visible area that goes beyond the safe area and I want to have this Geolocation not centered within the visible area but within the part of the visible area that overlaps with the safe area. So I need the safe-area-inset-top value in JS. In my case reading the CSS value with getComputedPropertymight work though as I defer the map rendering to the next rendering cycle (for other reasons), but this is already a hacky solution, so it would be better not to build on top of it :-D

frederikheld avatar May 17 '24 11:05 frederikheld

Understandable. To support this use case, I would have to write logic for web and iOS as well. Which I'm deliberately trying to prevent - as opposed to the other solutions available. So I'm still not very eager to implement such functionality.

Also it's not possible to listen to safe area inset changes on web apparently: https://github.com/w3c/csswg-drafts/issues/2732, https://github.com/w3c/csswg-drafts/issues/2628

So you will have listen to screen size changes or something. This is not something I'm willing to get into. It will probably get messy and that's not something I'm looking forward to maintain. Especially since probably most users won't need it

tafelnl avatar May 17 '24 12:05 tafelnl

Ok, understandable. Would you accept a PR? I won't promise anything, but if I don't find a solution to my case, I might be looking into it.

frederikheld avatar May 17 '24 13:05 frederikheld

Yeah sure, go ahead! But to be honest, I can't give you any guarantees I will be merging it. It also depends a bit on the solution you end up finding and implementing. If it's - purely hypothetically - like 10 lines of code, it's a lot more likely for me to accept it and maintain it, than when it's like a few hundred lines of code.

tafelnl avatar May 17 '24 13:05 tafelnl

Hi, sorry for the slow response. Just came back from holiday!

There is a different plugin that does this: https://www.npmjs.com/package/capacitor-plugin-safe-area

I've never used it though, so no recommendation, just information.

Yeah true. However, people were complaining about the compatibility of the plugin with regards to capacitor v6.

So basically, my app now has an edge-to-edge design, which looks great. However, I'd like to add some margin or padding to the interactive content (e.g., buttons) to prevent them from overlapping with the notch. Currently, in the edge-to-edge layout, this issue occurs. It's essential that the interactive content remains clickable. This might align with Frederikheld's comments.

dirkcremers avatar May 25 '24 20:05 dirkcremers

@dirkcremers This is exactly what @capacitor-community/safe-area helps you with. It exposes the correct margins as CSS values so you can use them to set margins to your containers. @tafelnl updated the README.md to make this more clear.

My use case is a different one where I need the value in JavaScript. But yours sounds like it can be solved with pure CSS.

frederikheld avatar May 25 '24 20:05 frederikheld

Thanks for both your replies! I will try it out

dirkcremers avatar May 26 '24 17:05 dirkcremers

For iOS, having content below the notch or dynamic island would be bad UI. The safe are insets help to offset a view's content below. When we write code for multiple platforms (e.g. web & iOS), we will end up having no space above the view at all on web, which again looks cluttered. If I now add additional margin on web, that will also be added to the one already applied by using the safe area insets on iOS, causing a larger, unnatural gap on the platform. I cannot apply conditional styles based on a CSS variable (except with some hacky min() max() trickery, which leads me to either having a larger than intended gap on iOS, or no gap at all on the web. If the values were accessible in JS (like they are in this package, I could render a gap only if no safe area inset given. Rendering the gap based on the platform will not work because we have iOS devices without notch. Or without bottom bar (older ones with home buttons).

efleetcon-simon-s avatar Apr 19 '25 04:04 efleetcon-simon-s

@efleetcon-simon-s

except with some hacky min() max() trickery

I think there might be a misunderstanding on how this plugins works. This plugins takes care of injecting the correct CSS variables, so you do not have to do any min/max trickery at all. You should just use the variables like in this example from the readme:

#header {
  padding-top: var(--safe-area-inset-top);
}

tafelnl avatar May 07 '25 12:05 tafelnl

I'm going to close this issue, as over the course of a year it didn't gain much traction and it's non-trivial to implement

tafelnl avatar May 07 '25 12:05 tafelnl

We do understand how the plugin works . It's just not enough to handle all issues that come with safe are insets. The plugin only covers the CSS side of the solution. It would be good to have the JS side covered as well because a web app has both.

frederikheld avatar May 08 '25 12:05 frederikheld

I was replying specifically to @efleetcon-simon-s in whose comment I do not see such a use case mentioned

tafelnl avatar May 08 '25 13:05 tafelnl