position: fixed is not working in iOS when loading Angular site inside iframe in Ionic 3 - ios

Brief Description on what we are trying to achieve
We are developing an Angular application. We developed it for both Web and Mobile using same code base. Mobile version contains lot of features such as Push Notifications, SMS Subscriptions etc. We are hoping to publish mobile version to App store and Play store. We are using simple Ionic 3 app to build it to Android and iOS.
Ionic 3 application contains only one page in which we are loading our Angular Web Site inside an iframe.
HTML of Ionic page
<ion-content>
<iframe class= 'webPage' [src]="iframeSrc" webkitAllowFullScreen mozallowfullscreen allowFullScreen>
</iframe>
</ion-content>
TS of Ionic page
export class HomePage {
iframeSrc: any;
sanitizer: DomSanitizer;
url: string = 'https://angular-load-ionic-iframe.stackblitz.io';
constructor( sanitizer: DomSanitizer ) {
this.sanitizer = sanitizer;
this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl(this.url);
}
}
Find The Github Repository of Ionic 3 app Here.
I have created StackBlitz Angular project which similar to My Angular application. Find it Here.
My Issue
In my application, app-header and app-footer need to be fixed to
ViewPort and other content should be able to scroll. I successfully
achieved this for Android But in iOS, app-header and app-footer
are not fixed to ViewPort and those are scrolling with other content
when I load my Angular application inside an iframe in Ionic app.
header.component.html
<header>
<div class="main">
<h3>Countries</h3>
</div>
</header>
header.component.css
.main {
background-color: #46454A;
color: rgba(255,255,255,.6);
padding:5px 50px;
}
header{
position: fixed;
z-index: 10;
top: 0;
width: 100%;
}
footer.component.html
<footer class="footer">
<h3>This is footer</h3>
</footer>
footer.component.css
.footer{
position: fixed;
bottom: 0;
width: 100%;
background-color:#47454b;
}
h3 {
color: white;
padding:0px 50px;
}
I couldn't figure out Is it CSS issue with iOS or Is it occurred as I load angular web site inside iframe. Struggling for one day but still no success. If anyone can help me to fix this issue highly appreciated and If someone need more details about this feel free to comment.

put this css in your style.css
body {
margin: 0px;
}
h3 {
color: white;
padding:0px 50px;
}
my-app{
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
app-header,app-home,app-footer{
position: absolute;
left: 0;
width: 100%;
}
app-header,app-footer{
text-align: center;
color: white;
height: 50px;
background-color:#47454b;
}
app-header{
top:0;
}
app-footer{
bottom:0;
}
app-home {
top: 50px;
bottom: 50px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
remove all css of header.component.css and footer.component.css
here is stackblitz link https://stackblitz.com/edit/angular-load-ionic-iframe-knkgq4?file=src%2Fstyles.css

Have you tried just setting the entire app mode / platform style to md via the app config? If you are able to solve this problem on Android then perhaps adopting Android styles globally for the iOS version will solve it for that platform too?
// app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import { IonicModule } from '#ionic/angular';
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
import { FooterComponent } from './footer/footer.component';
import { HomeComponent } from './home/home.component';
#NgModule({
imports: [
BrowserModule, FormsModule,
IonicModule.forRoot({
mode: 'md'
}),
],
declarations: [ AppComponent, HeaderComponent, FooterComponent, HomeComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }

Im not familiar with ionic and your angular setup but: there is a similar position fixed bug in safari Browsers.
The problem is: you cant position fixed Elements that are direct Children of the body tag.
The solution is: wrapping the content in another div. And putting every inside it.
Maybe you can try to put your Header and footer element inside an extra div so the footer isnt a direct child of the body tag.

Not tried, but worth a try:
style.css
body {
margin: 0px;
position: sticky;
z-index: -1;
width: 100%;
}
home.component.html
<div style="display: block;">
<div class="container" *ngFor="let country of countries">
<div class="code"><strong>Code:</strong> {{country.countryCode}}</div>
<div class="name"><strong>Name:</strong> {{country.countryName}}</div>
</div>
</div>
footer.component.css
.footer{
position: fixed;
bottom: 0;
width: 100%;
background-color:#47454b;
z-index:99;
}
h3 {
color: white;
padding:0px 50px;
}
I had similar issues in IE with sticky footer and header, this does the trick for me. You said that you are using iframes, but could not find some in your fork, only div-wrapped content... if you include the iframe, you can try to apply a relative positioning for the iframe like
position: relative;
to avoid collision with the header and footer. Hope this helps.

Related

Anchor links not working with scroll snapping

I am using the following script to enable scroll snapping:
<style>
.scroll-snap-wrapper {
overflow: scroll;
scroll-snap-type: y mandatory;
scroll-behavior: smooth;
height: 100vh; /* Fallback for browsers that do not support Custom Properties */
height: calc(var(--vh, 1vh) * 100);
}
.section-waitlist-lp {
height: 100vh;
scroll-snap-align: start;
}
.section-waitlist-lp-last {
scroll-snap-align: end;
}
.scroll-snap-wrapper {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scroll-snap-wrapper::-webkit-scrollbar {
display: none;
}
</style>
Now an anchor link that I set on one of the buttons …
<a id="lp-button-2" href="#buttontarget" class="button-waitlist-lp-secondary w-button" style="display: block;">Find out more</a>
… doesn't work anymore, targeting the second section on the page
<div id="buttontarget" class="section-waitlist-lp wf-section">
I had a look at this question + answer on here based on this solution, but it didn't work for me. The staging site can be found here.
Any ideas? Thank you!

is it possible to customize the vue components?

Is it possible to customize the vue components that quasar has?
I want to use the color picker vue component from the quasar framework (this one https://quasar.dev/vue-components/color-picker), but i wanted to remove the header and keep the hexadecimal color input.
I know there is a "no header" version of the component, but that version also removes the color input.
Here an image to exemplify
I want to keep the green part and remove the red part
You can hide the header completely and add a custom header which shows value of the current color.
<link href="https://cdn.jsdelivr.net/npm/quasar#1.8.3/dist/quasar.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#1.8.3/dist/quasar.umd.min.js"></script>
<div id="q-app">
<div class="q-pa-md">
<div class="container">
<div class="custom-header">{{hex}}</div>
<q-color no-header v-model="hex" dark class="my-picker" ></q-color>
</div>
</div>
</div>
<script>
new Vue({
el: '#q-app',
data () {
return {
hex: '#FF00FF'
}
}
})
</script>
<style>
.my-picker{
width: 150px
}
.container {
width: 180px;
position: relative;
}
.custom-header {
text-align: center;
background: transparent;
position: absolute;
width: 100%;
top: 0;
left: 0;
z-index: 10000
}
</style>
codepen

iOS Safari issue - Element becomes invisible while scrolling when changing position absolute to fixed

I want to use an element on the page as the title of the following content, but when the user is scrolling into the content this title-element should be fixed at the header. Similar to the ABC-captions in the iOS music-app.
See here: https://jsfiddle.net/1e7ync4w/
HTML
<div>
<div class="top">
Test
</div>
<div class="content">
<div class="scroller">
</div>
Test
</div>
</div>
CSS
.top {
background-color: yellow;
height: 300px;
}
.content {
position: relative;
height: 600px;
background-color: green;
}
.scroller {
position: absolute;
width: 100%;
height: 10px;
top: 0;
left: 0;
background-color: blue;
}
.scroller.fixed {
position: fixed;
}
JS
$(document).ready(function() {
$(window).on('scroll touchmove', function() {
$('.scroller').removeClass('fixed');
var scrollTop = $(window).scrollTop();
var scrollerOffsetTop = $('.scroller').offset().top;
if(scrollerOffsetTop <= scrollTop) {
$('.scroller').addClass('fixed');
}
});
});
The problem is that the iOS safari seems to have a bug with changing elements to fixed (via JavaScript) while scrolling. As soon as the user scrolls into the content, the title-element becomes invisible but shows after releasing the finger from the display (scroll-end).
I only tested this on the iOS 9.3.2 safari but I think this issue is older.
I found a solution for this problem. It's a little bit hacky but the only workaround I found for this iOS-bug.
The GPU of the browser needs to be "activated" for updating the according element. This can be achieved by setting a transform: translate-style via JS as soon as the positioning jumped to fixed.
The code of the example would look like this:
$(document).ready(function () {
$(window).on('scroll touchmove', function () {
$('.scroller').removeClass('fixed');
var scrollTop = $(window).scrollTop();
var scrollerOffsetTop = $('.scroller').offset().top;
if (scrollerOffsetTop <= scrollTop) {
$('.scroller').addClass('fixed').css({
'transform': 'translate3d(0px,0px,0px)',
'-moz-transform': 'translate3d(0px,0px,0px)',
'-ms-transform': 'translate3d(0px,0px,0px)',
'-o-transform': 'translate3d(0px,0px,0px)',
'-webkit-transform': 'translate3d(0px,0px,0px)'
});
}
});
});

Align footer to the bottom of printed HTML page?

I have a standard website, and when printed (for PDF-making purposes on Safari OS X), I'd like the footer to align to the bottom of whatever printed page it is on — i.e. the last page of the document.
Like this:
Is that possible?
I have used a media query (#media print { }) for all other print stylesheet details (excluded for simplicity).
Demo code is here; for the screen page itself, here is the HTML:
<div id="footer">
<p>A bunch of example stuff inside here...</p>
</div>
Which is situated with absolute positioning:
#footer {
color: #fff;
background: #000;
width: 100%;
position: absolute;
bottom: 0px;
}
Bit of an old one but the answer is surely to use the #page:last selector, but you have to alter the CSS for the footer as well.
#footer { position: static; }
#page:last {
#bottom-center { content:element(footer) }
}

How can I make the YouTube player scale to the width of the page but also keep the aspect ratio?

I have a YouTube video I want to put on my web page.
I want to scale the video to fit to a percent of the users browser but also to keep the aspect ratio.
I have tried this:
<iframe width="87%" height="315" src="http://www.youtube-nocookie.com/embed/dU6OLsnmz7o" frameborder="0" allowfullscreen></iframe>
But that does only make the player wider, not higher.
Does I have to resort to JavaScript (or non-standard CSS)?
What i believe to be the best CSS solution.
.auto-resizable-iframe {
max-width: 420px;
margin: 0px auto;
}
.auto-resizable-iframe > div {
position: relative;
padding-bottom: 75%;
height: 0px;
}
.auto-resizable-iframe iframe {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
}
<div class="auto-resizable-iframe">
<div>
<iframe frameborder="0" allowfullscreen="" src="http://www.youtube.com/embed/_OBlgSz8sSM"></iframe>
</div>
</div>
Demo http://jsfiddle.net/46vp592y/
I hit a similar issue with my site when developing some responsive CSS. I wanted any embedded Youtube objects to resize, with aspect, when switching from the desktop CSS to something smaller (I use media queries to re-render content for mobile devices).
The solution I settled on was CSS and mark-up based. Basically, I have three video classes in my CSS thus:
.video640 {width: 640px; height: 385px}
.video560 {width: 560px; height: 340px}
.video480 {width: 480px; height: 385px}
… and I assign one of these to the Youtube content I include, depending on its original size (you may need more classes, I just picked the most common sizes).
In the media query CSS for smaller devices, these same classes are simply re-stated like so:
.video640 {width: 230px; height: 197px}
.video560 {width: 230px; height: 170px}
.video480 {width: 240px; height: 193px}
I appreciate this requires some mark-up "up-front" when including videos in your HTML (i.e. adding a class), but if you don't want to go down the Javascript route, this works pretty well -- you could re-state your video classes for as many different sizes as you require. Here's how the Youtube mark-up looks:
<object class="video640" type="application/x-shockwave-flash" value="YOUTUBE URL">
<param name="movie" value="YOUTUBE URL"></param>
</object>
Quite easy with some javascript.
jQuery(function() {
function setAspectRatio() {
jQuery('iframe').each(function() {
jQuery(this).css('height', jQuery(this).width() * 9/16);
});
}
setAspectRatio();
jQuery(window).resize(setAspectRatio);
});
This jQuery plugin has been making the rounds of late, it's called FitVids and does exactly what you need, resizes videos based on browser size whilst maintaining aspect ratio.
http://fitvidsjs.com/
Modern Solution (2022) - aspect-ratio
With the introduction of the aspect-ratio property in CSS, it's now very simple to scale a YouTube video without resorting to CSS hacks or JS.
Example:
iframe {
aspect-ratio: 16 / 9;
height: auto;
width: 100%;
}
The aspect-ratio property is widely supported across browsers making it suitable for the vast majority of sites: https://caniuse.com/mdn-css_properties_aspect-ratio
These work a treat no JS. Responsive for both single palyer and list player modified from somewhere not sure, no credit sorry. Load your iframe Youtube player inside a container div, the iframe style sets the player specific sizing, 100% will fill the container to any size, src= your-youtube-ID, add own player options
https://jsfiddle.net/jcb01/04sf3byz/
<div style=" position: relative; padding-bottom: 56.25%;">
<!--- load iframe Youtube player inside this div -->
<iframe
style="border: 1; top: 0; left: 0; width: 100%; height: 100%; position: absolute;"
src="https://www.youtube-nocookie.com/embed/?
list=PL590L5WQmH8fmto8QIHxA9oU7PLVa3ntk;
&autoplay=0&enablejsapi=1&index=0&
listType=playlist&loop=1&modestbranding=1"
allowfullscreen scrolling="no"
allow="encrypted-media; accelerometer;
gyroscope; picture-in-picture">
</iframe>
</div>
The trick to make a youtube video autoresize is to make the iframe width 100% and put it in a div with a "padding-bottom" equal to the aspect ratio in percentage. E.g.
But the problem is - you would have a lot of pages with embedded YoutTube videos already. Here's a jquery plugin that will scan all videos on the page and make them resizable automatically by changing the iframe code to be as above. That means you don't have to change any code. Include the javascript and all your YouTube videos become autoresizing.
https://skipser.googlecode.com/files/youtube-autoresizer.js
Old question, but I think the #media CSS 3 tags would be helpful in this instance.
Here is my solution to a similar problem.
The CSS:
#media only screen and (min-width: 769px) {
.yVid {
width: 640px;
height: 360px;
margin: 0 auto;
}
}
#media only screen and (max-width: 768px) {
.yVid {
width: 560px;
height: 315px;
margin: 0 auto;
}
}
The HTML:
<div class="yVid">
<iframe width="100%" height="100%" frameborder="0" allowfullscreen="" src="http://www.youtube.com/embed/_OBlgSz8sSM"></iframe>
</div>
This basically adds a breakpoint at 768px where the video resizes itself. You could also add breakpoints at 992 and 1280 for an even more repsonsive video size. (numbers based on Bootstrap standard sizes).
This is what worked for me. This is slightly modified code from the YouTube Embed Code Generator.
The CSS:
.video-container {
position: relative;
width: 100%;
height: 0;
padding-bottom: 56.27198%;
}
.video-container iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
The HTML:
<div class="video-container">
<iframe width="560px" height="315px" src="https://www.youtube.com/embed/XXXXxxxx?&theme=dark&autohide=2&iv_load_policy=3"><iframe>
</div>
You can use style="max-width: %87; max-height: %87;"
In addition to Darwin and Todd the following solution will
avoid the bottom margin
maximize the width for large screens
minimize the height in mobile view
keep a fixed size for #media none compatible browsers
The HTML:
<div class="video_player">
<div class="auto-resizable-iframe">
<div>
<iframe frameborder="0" allowfullscreen="" src="http://www.youtube.com/embed/_OBlgSz8sSM"> </iframe>
</div>
</div>
</div>
The CSS:
.videoplayer{
text-align: center;
vertical-align: middle;
background-color:#000000;
margin: 0;
padding: 0;
width: 100%;
height:420px;
overflow:hidden;
top: 0;
bottom: 0;
}
.auto-resizable-iframe {
width:100%;
max-width:100%;
margin: 0px auto;
}
.auto-resizable-iframe > div {
position: relative;
padding-bottom:420px;
height: 0px;
}
.auto-resizable-iframe iframe {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
}
//full screen
#media (min-width:0px) {
.videoplayer{
height:100%;
}
.auto-resizable-iframe > div {
padding-bottom:100%;
}
}
//mobile/pad view
#media (min-width:600px) {
.videoplayer{
height:420px;
}
.auto-resizable-iframe > div {
padding-bottom:420px;
}
}
There are a few suggestions on the list of answers to use js to modify the structure of generated iframe. I think there is a risk with that because when you wrap the iframe inside other elements it's possible that the YouTube API will lose 'connection' with the iframe (especially if you pass the element in as a node instead of using specific id like me). It's rather to get around it actually, use javascript to modify the content before you actually trigger the youtube player.
a snippet from my code:
/**
* Given the player container, we will generate a new structure like this
*
* <div class="this-is-the-container">
* <div class="video-player">
* <div class="auto-resizable-iframe">
* <div>
* <iframe frameborder="0" allowfullscreen="" src="http://www.youtube.com/embed/_OBlgSz8sSM"> </iframe>
* </div>
* </div>
* </div>
* </div>
*
* #return {Node} the real player node deep inside
*/
YouTube.renderResizable = function (playerContainer) {
// clean up the content of player container
playerContainer.textContent = '';
var playerDiv = document.createElement('div');
playerDiv.setAttribute('class', 'video-player');
playerContainer.appendChild(playerDiv);
// add the auto-resizable-frame-div
var resizeableDiv = document.createElement('div');
resizeableDiv.setAttribute('class', 'auto-resizable-iframe');
playerDiv.appendChild(resizeableDiv);
// create the empty div
var div = document.createElement('div');
resizeableDiv.appendChild(div);
// create the real player
var player = document.createElement('div');
div.appendChild(player);
return player;
};
Just set iframe height and width with CSS vw metric. It uses device width as parameter:
.videoWrapper iframe {
height: 36.6vw;
width: 65vw;
}
You could use two classes that would scale the size of the video based on the size of the wrapping div. Consider this example:
<div class="content-wrapper">
<div class="iframe-wrapper res-16by9">
<iframe src="https://www.youtube.com/embed/pHsYFURtzzY" frameborder="0" allowfullscreen></iframe>
</div>
</div>
Now look at the css.
.content-wrapper{
max-width: 800px;
margin: 0 auto;
background-color: #fff;
}
.iframe-wrapper{
width: 100%;
position: relative;
}
.res-4by3{
padding-bottom: 75%;
}
.res-16by9{
padding-bottom: 56.25%;
}
.iframe-wrapper iframe{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
Note that you will have to wrap the iframe in a div who's width is set to 100% and position is set to relative. You have to also add a bottom-padding to iframe wrapper. This padding will define the height of a video. I recommend to create two classes that will represent the image ratio.
It is quite easy to calculate the right bottom-padding for wrappers that represent certain resolution. For example for res 4 by 3 and 16 by 9 would have bottom-padding equal to:
[4/3 res]
100 / 4 * 3 = 75%;
[16/9 res]
100 / 16 * 9 = 56.25%
Then position the iframe as absolute and push it to the top left corner of the wraping div. Also meke sure to set iframe width and height to 100%. You are done.
Add the class that fits the right resolution for you. It will scale the image width and height respectively keeping the right proportions in place.
The example above works for any iframe. Thats mean you can also use it for google maps iframe.
Add JavaScript code to give each youtube iFrame a class:
$('iframe[src*="youtube"]').addClass('youtube')
Then in the Media Queries use the you tube class to set a different size.
.youtube {
/* Do stuff here */
}
Easier and optimized to CMS than the manual way.

Resources