Jak sprawić, by ramka iFrame była responsywna w iOS Safari?

134

Problem polega na tym, że kiedy musisz używać ramek iFrame do wstawiania treści do strony internetowej, to we współczesnym świecie internetowym oczekuje się, że ramka iFrame również będzie responsywna. W teorii to proste, po prostu użyj pomocy <iframe width="100%"></iframe>lub ustaw szerokość CSS na, iframe { width: 100%; }jednak w praktyce nie jest to takie proste, ale może być.

Jeśli iframezawartość jest w pełni responsywna i może zmieniać swój rozmiar bez wewnętrznych pasków przewijania, iOS Safari zmieni rozmiar iframebez żadnych rzeczywistych problemów.

Jeśli weźmiesz pod uwagę następujący kod:

<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=9,10,11" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Iframe Isolation Test</title>

    <style type="text/css" rel="stylesheet">

        #Main {
            padding: 10px;
        }
    </style>
</head>
<body>
    <h1>Iframe Isolation Test 13.17</h1>
    <div id="Main">
        <iframe height="950" width="100%" src="Content.html"></iframe>
    </div>
</body>
</html>

Z Content.html :

<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=9,10,11" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Iframe Isolation Test - Content</title>

    <style type="text/css" rel="stylesheet">

        #Main {
            width: 100%;
            background: #ccc;
        }

    </style>
</head>
<body>
    <div id="Main">
        <div id="ScrolledArea">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc malesuada purus quis commodo convallis. Fusce consectetur mauris eget purus tristique blandit. Nam nec volutpat augue. Aliquam sit amet augue vitae orci fermentum tempor sit amet gravida augue. Pellentesque convallis velit eu malesuada malesuada. Aliquam erat volutpat. Nam sollicitudin nulla nec neque viverra, non suscipit purus tincidunt. Aenean blandit nisi felis, sit amet ornare mi vestibulum ac. Praesent ultrices varius arcu quis fringilla. In vitae dui consequat, rutrum sapien ut, aliquam metus. Proin sit amet porta velit, suscipit dignissim arcu. Cras bibendum tellus eu facilisis sodales. Vestibulum posuere, magna ut iaculis consequat, tortor erat vulputate diam, ut pharetra sapien massa ut magna. Donec massa purus, pharetra sed pellentesque nec, posuere ut velit. Nam venenatis feugiat odio quis tristique. 
        </div>      
    </div>
</body>
</html>

Wtedy działa to bez problemów w iOS 7.1 Safari. Możesz bez problemu przełączać się między orientacją poziomą i pionową.

wprowadź opis obrazu tutaj wprowadź opis obrazu tutaj

Jednak po prostu zmieniając Content.html CSS, dodając:

    #ScrolledArea {
        width: 100%;
        overflow: scroll;
        white-space: nowrap;
        background: #ff0000;
    }

Otrzymujesz to:

wprowadź opis obrazu tutaj wprowadź opis obrazu tutaj

Jak widać, mimo że zawartość Content.html jest w pełni responsywna ( div # ScrolledArea maoverflow: scroll ustawione) i iframe szerokość wynosi 100% iframe nadal trwa pełną szerokość div # ScrolledArea jakby przelewowy nawet nie istnieje. Próbny

W takich przypadkach, czy iframetreść ma przewijane obszary, pojawia się pytanie, jak uzyskać iframeresponsywność, kiedy zawartość iframe ma obszary przewijane w poziomie? Problem tutaj nie polega na tym, że Content.html nie jest responsywny, ale na fakcie, że iOS Safari po prostu zmienia rozmiar iframe tak, div#ScrolledAreaaby był w pełni widoczny.

Idra
źródło
Czy możesz udostępnić nam link? Czy twierdzisz, że iOS rozszerzy ramkę iFrame do pełnej szerokości strony, jeśli strona w niej zawiera white-space: nowrapstylową treść ?
DA.
@DA Dodałem dema do problemu i rozwiązania. I nie, white-space: nowrapsamo w sobie nie jest problemem. Po prostu używam go, aby uzyskać ekstremalną szerokość div#ScrolledArea. Problem pojawia się, gdy zawartość iFrame zawiera obszary przewijalne w poziomie. W takim przypadku iOS Safari po prostu ignoruje ustawienia szerokości i pokazuje zawartość dziury oraz przerywa czas reakcji witryny.
Idra
Hmm ... Zastanawiam się, czy to „funkcja”. Byłoby niewygodne mieć przewijalny obszar (iFrame) zawierający przewijalną zawartość. Byłby bardzo trudny do interakcji na ekranie dotykowym.
DA.
@DA Oczywiście jest to przypadek siostrzenicy i to, co powiedziałeś, może być prawdą (zależy od implementacji, działa dla nas), a większość witryn nie ma obszarów przewijanych w poziomie, ale kiedy to zrobisz ... nie możesz sobie nawet wyobrazić ile czasu nad tym spędziłem. Ale może to stanowić problem, nawet jeśli masz obrazy, które są ukryte i przewijane za pomocą przycisków lub czegoś podobnego.
Idra
Wygląda na to, że są powiązane pytania na ten temat: stackoverflow.com/questions/5267996/… Wygląda na to, że jest to „funkcja” mobilnego safari… próbuje upewnić się, że zawartość jest dopasowana do rozmiaru umożliwiającego użytkownikowi nadal z nim współdziałać. Nie jestem pewien, co by się stało, gdybyś zawierał przewijaną zawartość w przewijanej ramce iframe ... jak Safari zinterpretowałby przesunięcie w zagnieżdżonych elementach przewijania?
DA.

Odpowiedzi:

289

Rozwiązanie tego problemu jest w rzeczywistości dość proste i można to zrobić na dwa sposoby. Jeśli masz kontrolę nad Content.html, po prostu zmień div#ScrolledAreaszerokość CSS na:

        width: 1px;
        min-width: 100%;
        *width: 100%;

Zasadniczo pomysł jest tutaj prosty, ustawiasz widthcoś, co jest mniejsze niż widok (w tym przypadku szerokość ramki iframe), a następnie nadpisujesz ją, min-width: 100%aby umożliwić faktyczne width: 100%nadpisanie przeglądarki Safari w iOS. *width: 100%;Jest tak kod pozostanie IE6 kompatybilne, ale jeśli nie obchodzi dla IE6 można go pominąć. Próbny

wprowadź opis obrazu tutaj wprowadź opis obrazu tutaj

Jak widać, div#ScrolledAreaszerokość w rzeczywistości wynosi 100% i overflow: scroll;można to zrobić i ukryć przepełnioną zawartość. Jeśli masz dostęp do zawartości iframe, jest to preferowane.

Jeśli jednak nie masz dostępu do zawartości elementu iframe (z dowolnego powodu), możesz faktycznie użyć tej samej techniki w samym elemencie iframe. Po prostu użyj tego samego kodu CSS w ramce iframe:

    iframe {
        width: 1px;
        min-width: 100%;
        *width: 100%;
    }

Jest jednak jedno ograniczenie, musisz wyłączyć paski przewijania w elemencie scrolling="no"iframe, aby to zadziałało:

<iframe height="950" width="100%" scrolling="no" src="Content.html"></iframe>

Jeśli paski przewijania są dozwolone, to nie będzie już działać w elemencie iframe. To powiedziawszy, jeśli zamiast tego zmodyfikujesz Content.html , możesz zachować przewijanie w ramce iframe. Próbny

Idra
źródło
1
Jak wspomniał @NickGottlieb, musiałem dodać !importantdo widthatrybutu, aby przygotować responsywną ramkę iframe na iPhone 4 z iOS 7
malisokan
@ ЮнгвиртТони Nie powinno być potrzebne, aby obejście zadziałało, możliwe, że widthzostało ustawione wcześniej !importantlub nadpisano CSS o wyższym priorytecie. W pojedynczych przypadkach w iPhone 4 iOS7 nie było to potrzebne.
Idra
Nie potrzebowałem! Ważne też. Działa również świetnie na iOS 8. Pozdrawiam
Sam Potts
Potrzebuję przewijania = nie tylko wtedy, gdy jest to konieczne, w przeciwnym razie przewijania = tak. Więc co powinienem wykrywać? Czy to problem z iOS? lub problem z zestawem internetowym? lub...?
gerbz
@ggwarpig jest to problem z systemem iOS, w którym iOS Safari automatycznie włącza atrybut bezproblemowy i nie można go nadpisać. Jeśli masz kontrolę nad zawartością, musisz zmodyfikować zawartość, aby w scrolling="yes"przeciwnym razie nie ma sposobu, aby to naprawić, aby poprawka działała na ramce iFrame, wystarczy mieć scrolling="no"na IFRAME
Idra
24

Wydaje się, że problem polega na tym, że Mobile Safari odmówi przestrzegania szerokości ramki iFrame, jeśli dokument, który zawiera, jest szerszy niż określony. Przykład:

http://jsbin.com/hapituto/1

W przeglądarce na komputerze zobaczysz element iFrame i element Div ustawione na 300 pikseli. Zawartość jest szersza, dzięki czemu można przewijać element iFrame.

Jednak w mobilnym safari zauważysz, że element iFrame jest automatycznie rozszerzany do szerokości treści.

Domyślam się, że jest to obejście długotrwałych problemów z przewijaniem treści na stronie. W przeszłości, gdybyś miał duży przewijany element iframe na urządzeniu dotykowym, „utknął” w elemencie iframe, ponieważ przewijał się on zamiast samej strony. Wygląda na to, że Apple zdecydował, że domyślnym zachowaniem elementu iFrame jest „brak przewijania” i rozszerza się, aby temu zapobiec.

Jedną z opcji może być to obejście. Zamiast zakładać, że element iFrame będzie się przewijał, umieść element iframe w sekcji DIV, nad którą masz kontrolę, i pozwól jej przewijać.

przykład: http://jsbin.com/zakedaja/1

Przykładowe znaczniki:

<div style="overflow: scroll; -webkit-overflow-scrolling: touch; width: 300px;">
   <iframe src="http://jsbin.com/roredora/1/" style="width: 600px;"></iframe>
</div>

W mobilnym safari możesz teraz przewijać zawartość w pełni rozwiniętego elementu iFrame za pośrednictwem zawierającego go elementu div.

Haczyk: wygląda to naprawdę brzydko w przeglądarce na komputerze, ponieważ teraz masz podwójne paski przewijania. Być może będziesz musiał wykonać pewne wykrywanie przeglądarki za pomocą JS, aby obejść ten problem.

DA.
źródło
1
Nadal twierdzę, że nie jest to tak naprawdę objęte zakresem pytania, ponieważ rozwiązanie, które tutaj pokazałeś, to standardowy sposób na sfałszowanie przewijania ramek iframe z otworem w iOS Safari, ale biorąc pod uwagę ten problem z iOS, jest to kwestia przewijania IFrame (treści lub w inny sposób) to miło jest mieć to tutaj.
Idra
1
Chyba nie do końca rozumiem twoje pytanie. Z tego, co rozumiem, problem polega na tym, że w iOS Mobile Safari próbuje przede wszystkim zapobiec przewijaniu iFrame i wymusza na nim szerokość. Czy źle rozumiem twój problem?
DA.
W istocie na tym polega problem, jego właśnie wymagane rozwiązanie jest inne. W początkowym problemie zawartość iFrame była responsywna, podczas gdy zawartość przewijana była w poziomie, więc nie chodziło o to, jak emulować przewijanie iframe , ale jak sprawić, by szerokość iframe była 100%, czyli responsywna, podczas gdy zawartość przewijana jest w poziomie że iframe. Dlatego powyższe podejście nie działa w tym przypadku, ponieważ zaprojektowana responsywność została zepsuta i musisz przewijać, aby zobaczyć pełną zawartość, nawet w miejscach, w których normalnie nie musiałbyś tego robić.
Idra
1
Przepraszam, zdałem sobie sprawę, że wprowadziłem Cię w błąd jednym z komentarzy. Element iframe nie przewija się. O to właśnie chodziło, element iframe nie miał przewijać tylko części swojej zawartości, tj. div#ScrolledArea(Na zielono) w moim przykładzie. Po prostu źle przeczytałem wcześniej. Ale element iframe nie powinien przewijać się, tylko zmieniając swój rozmiar na podstawie elementu kontenera, czyli miećwidth: 100%;
Idra
18

Potrzebowałem rozwiązania obsługującego wiele przeglądarek. Wymagania były następujące:

  • potrzebne do pracy zarówno na iOS, jak i gdzie indziej
  • nie mają dostępu do zawartości w iFrame
  • trzeba go przewijać!

Opierając się na tym, czego nauczyłem się od @Idra odnośnie przewijania = „nie” na iOS i na tym poście o dopasowywaniu zawartości iFrame do ekranu w iOS, oto co skończyłem. Mam nadzieję, że to komuś pomoże =)

HTML

<div id="url-wrapper"></div>

CSS

html, body{
    height: 100%;
}

#url-wrapper{
    margin-top: 51px;
    height: 100%;
}

#url-wrapper iframe{
    height: 100%;
    width: 100%;
}

#url-wrapper.ios{
    overflow-y: auto;
    -webkit-overflow-scrolling:touch !important;
    height: 100%;
}

#url-wrapper.ios iframe{
    height: 100%;
    min-width: 100%;
    width: 100px;
    *width: 100%;
}

JS

function create_iframe(url){

    var wrapper = jQuery('#url-wrapper');

    if(navigator.userAgent.match(/(iPod|iPhone|iPad)/)){
        wrapper.addClass('ios');
        var scrolling = 'no';
    }else{
        var scrolling = 'yes';
    }

    jQuery('<iframe>', {
        src: url,
        id:  'url',
        frameborder: 0,
        scrolling: scrolling
    }).appendTo(wrapper);

}
gerbz
źródło
1
przegłosowano, ale ... dlaczego reguła IE6 w klasie „ios”? :-)
J. Bruni
12

Problem z tymi wszystkimi rozwiązaniami polega na tym, że wysokość iframenigdy się tak naprawdę nie zmienia.

Oznacza to, że nie będziesz w stanie wyśrodkować elementów wewnątrz przy iframeużyciu Javascript position:fixed;lub position:absolute;ponieważ iframesam nigdy się nie przewija.

Moje rozwiązanie opisane tutaj polega na zawinięciu całej zawartości iframe wewnątrz elementu divprzy użyciu tego kodu CSS:

#wrap {
    position: fixed;
    top: 0;
    right:0;
    bottom:0;
    left: 0;
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
}

W ten sposób Safari uważa, że ​​zawartość nie ma wysokości i umożliwia iframeprawidłowe przypisanie wysokości . Pozwala to również na dowolne pozycjonowanie elementów.

Możesz zobaczyć szybkie i brudne demo tutaj.

Molo
źródło
1
To jedyne rozwiązanie, które u mnie zadziałało. Oczywiście można go używać tylko wtedy, gdy kontrolujesz zawartość iframe, ale w moim przypadku tak. Twoje zdrowie!
Vince
Hmm. Twój przykład nie reaguje na iOS?
BrandonReid
Napisałem to 2 lata temu. Czy możesz zgłosić problem w repozytorium?
Przystań
po marnowaniu godzin na ten problem z Ionic / Cordova na iOS, to jedyna rzecz, która zadziałała. dzięki!
Andrew
1
To jest niesamowite, jedyne, które zadziałało, spędziłem 1 dzień na poszukiwaniu rozwiązania takiego @Pier 100pkt dla ciebie
Carlos E
5

Ten problem występuje również w iOS Chrome.

Przejrzałem wszystkie powyższe rozwiązania, większość z nich jest bardzo hakerska.

Jeśli nie potrzebujesz obsługi starszych przeglądarek, po prostu ustaw szerokość ramki iframe na 100vw;

iframe {
  max-width: 100%; /* Limits width to 100% of container */
  width: 100vw; /* Sets width to 100% of the viewport width while respecting the max-width above */
}

Uwaga: sprawdź obsługę jednostek widoku https://caniuse.com/#feat=viewport-units

Prathamesh Gharat
źródło
1
Chrome na iOS to tylko Safari. Używa WKWebView. Żaden inny silnik renderowania internetowego nie jest dozwolony w iOS.
Przystań
3

Pracuję z ionic2, a konfiguracja systemu jest jak poniżej-


******************************************************

Your system information:

Cordova CLI: 6.4.0 
Ionic Framework Version: 2.0.0-beta.10
Ionic CLI Version: 2.1.8
Ionic App Lib Version: 2.1.4
ios-deploy version: Not installed
ios-sim version: 5.0.8 
OS: OS X Yosemite
Node Version: v6.2.2
Xcode version: Xcode 7.2 Build version 7C68



******************************************************

U mnie ten problem został rozwiązany za pomocą tego kodu -
dla tagu iframe HTML -

<div class="iframe_container">
      <iframe class= "animated fadeInUp" id="iframe1" [src]='page' frameborder="0" >
        <!--  <img src="img/video-icon.png"> -->
      </iframe><br>
   </div>

Zobacz css tego samego co-


.iframe_container {
  overflow: auto; 
  position: relative; 
  -webkit-overflow-scrolling: touch;
  height: 75%;
}

iframe {
  position:relative;
  top: 2%;
  left: 5%;
  border: 0 !important;
  width: 90%;
}

Własność pozycji odgrywa w moim przypadku kluczową rolę.
pozycja: względna;

To też może ci pomóc !!!

S.Yadav
źródło
0

Tylko rozwiązanie CSS

HTML

<div class="container">
    <div class="h_iframe">
        <iframe  src="//www.youtube.com/embed/9KunP3sZyI0" frameborder="0" allowfullscreen></iframe>
    </div>
</div>

CSS

html,body {
    height:100%;
}
.h_iframe iframe {
    position:absolute;
    top:0;
    left:0;
    width:100%;
    height:100%;
}

PRÓBNY

Kolejne demo ze stroną HTML w ramce iframe

4dgaurav
źródło
Może niepoprawnie implementuję twoje rozwiązanie, ale kiedy wypróbowałem je z moim izolowanym przypadkiem testowym, to w ogóle nie działało w iOS Safari 7.1 iPhone 4. Czy mógłbyś wyjaśnić, jak to powinno działać?
Idra
OK, wygląda na to, że źle zrozumiałeś problem. Sprawdź ten link, aby zobaczyć , że jest to Twoja nowa zawartość elementu iframe w wersji demonstracyjnej zintegrowana bez dodatkowego kodu CSS zastosowanego do elementu iframe. A jeśli spojrzysz na to w iOS Safari, to nadal jest responsywna, ponieważ ta strona nie ma żadnego poziomego przewijania, które wymusiłoby szerokość elementu iframe szerszą niż widok. Jak opisano w pytaniu, w witrynie takiej jak ta nie musisz nic robić, aby element iframe był responsywny.
Idra
więc co dokładnie chcesz, żeby się zachowywał, podaj przykład dla podanego linku?
4dgaurav
0

Wystąpił problem z szerokością okienka zawartości, tworząc poziomy pasek przewijania dla elementu iframe. Okazało się, że obraz miał szerokość szerszą niż oczekiwano. Udało mi się to rozwiązać, ustawiając wszystkie obrazy css max-width na procent.

<meta name="viewport" content="width=device-width, initial-scale=1" />

img {
        max-width: 100%;
        height:auto;
    }
Dr Aaron Dishno
źródło
0

w rzeczywistości dla mnie właśnie działało w iOS wyłączanie przewijania

<iframe src="//www.youraddress.com/" scrolling="no"></iframe>

i traktowanie systemu operacyjnego za pomocą skryptu.

Luiz Rossi
źródło
0

U mnie rozwiązania CSS nie działały. Ale programowe ustawienie szerokości spełnia swoje zadanie. Podczas ładowania elementu iframe ustaw szerokość programowo:

 $('iframe').width('100%');
umer
źródło