पहलू अनुपात धारणा के बिना एक iframe उत्तरदायी कैसे बना सकता है?


14

एक पहलू अनुपात ग्रहण किए बिना, एक आइफ्रेम को उत्तरदायी कैसे बनाया जाए? उदाहरण के लिए, सामग्री में कोई चौड़ाई या ऊँचाई हो सकती है, जो रेंडर करने से पहले अज्ञात है।

ध्यान दें, आप जावास्क्रिप्ट का उपयोग कर सकते हैं।

उदाहरण:

<div id="iframe-container">
    <iframe/>
</div>

इसे आकार दें iframe-containerताकि इसकी सामग्री अतिरिक्त जगह के बिना मुश्किल से अंदर फिट हो, दूसरे शब्दों में, सामग्री के लिए पर्याप्त जगह है इसलिए इसे स्क्रॉल किए बिना दिखाया जा सकता है, लेकिन कोई अतिरिक्त स्थान नहीं। कंटेनर आईफ्रेम को पूरी तरह से लपेटता है।

यह दिखाता है कि एक आइफ्रेम को उत्तरदायी कैसे बनाया जाए, यह मानते हुए कि सामग्री का पहलू अनुपात 16: 9 है। लेकिन इस प्रश्न में, पहलू अनुपात परिवर्तनशील है।


1
मुझे एक संपादन @TravisJ
17

2
Iframe में सामग्री के आयामों की गणना करना संभव है, लेकिन यह वास्तव में कैसे किया जाना चाहिए, सामग्री पर थोड़ा सा निर्भर करता है, और बहुत सीएसएस का उपयोग किया जाता है (बिल्कुल तैनात सामग्री को मापने के लिए अत्यंत कठिन है)। यदि आप एक सीएसएस रीसेट फ़ाइल का उपयोग कर रहे हैं, तो परिणाम पृष्ठ से भिन्न होता है रीसेट फ़ाइल का उपयोग नहीं किया जाता है, और ब्राउज़र के बीच भी भिन्न होता है। आईफ्रेम और उसके अभिभावक का आकार तुच्छ है। इसलिए, हमें पृष्ठ की स्थिति के बारे में अधिक जानकारी की आवश्यकता होगी, विशेष रूप से इस्तेमाल किए गए CSS रीसेट फ़ाइल (एस) (या वास्तविक सीएसएस) का नाम (s), यदि आप किसी भी सामान्य फ़ाइल (s) का उपयोग नहीं कर रहे हैं।
तेमू

2
क्या आपके पास आईफ्रेम में लोड किए गए दस्तावेज़ पर नियंत्रण है? मेरा मतलब है, यदि आप नहीं करते हैं, तो कुछ भी नहीं है जो आप कर सकते हैं। सब कुछ iframe दस्तावेज़ के अंदर किया जाना है (या उस दस्तावेज़ तक पहुंच के द्वारा), अन्य यह बिल्कुल संभव नहीं है।
तैमू

1
नहीं, तो यह संभव नहीं है, डेवलपर . mozilla.org/en-US/docs/Web/Security/… देखें । मुख्य पृष्ठ सुरक्षा कारणों से iframe (और इसके विपरीत) में एक क्रॉस-डोमेन दस्तावेज़ तक नहीं पहुंच सकता है, इसे केवल तभी देखा जा सकता है जब आपके पास iframe में दिखाए गए दस्तावेज़ पर नियंत्रण हो।
तैमू

1
... इंटरनेट के 15 साल यह असंभव है पर्याप्त नहीं है? क्या हमें वास्तव में इस बारे में एक नए प्रश्न की आवश्यकता है?
काइदो

जवाबों:


8

जावास्क्रिप्ट का उपयोग करके एक अलग मूल iFrame के साथ बातचीत करना संभव नहीं है ताकि इसका आकार प्राप्त कर सके; यह करने के लिए एक ही रास्ता का उपयोग करना है window.postMessageके साथ targetOriginअपने डोमेन के लिए सेट या wildchar *iFrame स्रोत से। आप विभिन्न मूल साइटों और उपयोग की सामग्रियों को प्रॉक्सी कर सकते हैं srcdoc, लेकिन इसे हैक माना जाता है और यह एसपीए और कई अन्य अधिक गतिशील पृष्ठों के साथ काम नहीं करेगा।

एक ही मूल iFrame आकार

मान लें कि हमारे पास दो समान मूल iFrames हैं, एक छोटी ऊंचाई और निश्चित चौड़ाई:

<!-- iframe-short.html -->
<head>
  <style type="text/css">
    html, body { margin: 0 }
    body {
      width: 300px;
    }
  </style>
</head>
<body>
  <div>This is an iFrame</div>
  <span id="val">(val)</span>
</body>

और एक लंबी ऊंचाई iFrame:

<!-- iframe-long.html -->
<head>
  <style type="text/css">
    html, body { margin: 0 }
    #expander {
      height: 1200px; 
    }
  </style>
</head>
<body>
  <div>This is a long height iFrame Start</div>
  <span id="val">(val)</span>
  <div id="expander"></div>
  <div>This is a long height iFrame End</div>
  <span id="val">(val)</span>
</body>

हम loadइवेंट पर iFrame का आकार प्राप्त कर सकते हैं, iframe.contentWindow.documentजिसका उपयोग करके हम मूल विंडो पर भेजेंगे postMessage:

<div>
  <iframe id="iframe-local" src="iframe-short.html"></iframe>
</div>
<div>
  <iframe id="iframe-long" src="iframe-long.html"></iframe>
</div>

<script>

function iframeLoad() {
  window.top.postMessage({
    iframeWidth: this.contentWindow.document.body.scrollWidth,
    iframeHeight: this.contentWindow.document.body.scrollHeight,
    params: {
      id: this.getAttribute('id')
    }
  });
}

window.addEventListener('message', ({
  data: {
    iframeWidth,
    iframeHeight,
    params: {
      id
    } = {}
  }
}) => {
  // We add 6 pixels because we have "border-width: 3px" for all the iframes

  if (iframeWidth) {
    document.getElementById(id).style.width = `${iframeWidth + 6}px`;
  }

  if (iframeHeight) {
    document.getElementById(id).style.height = `${iframeHeight + 6}px`;
  }

}, false);

document.getElementById('iframe-local').addEventListener('load', iframeLoad);
document.getElementById('iframe-long').addEventListener('load', iframeLoad);

</script>

हम दोनों iFrames के लिए उचित चौड़ाई और ऊंचाई प्राप्त करेंगे; आप इसे यहाँ ऑनलाइन देख सकते हैं और यहाँ स्क्रीनशॉट देख सकते हैं

अलग मूल iFrame आकार हैक (पुनः नहीं मिला )

यहां वर्णित विधि एक हैक है और इसका उपयोग किया जाना चाहिए यदि यह बिल्कुल आवश्यक है और आसपास कोई अन्य तरीका नहीं है; यह सबसे गतिशील उत्पन्न पृष्ठों और एसपीए के लिए काम नहीं करेगा । विधि पृष्ठ HTML स्रोत कोड को एक प्रॉक्सी का उपयोग करके CORS पॉलिसी को बायपास करती है ( cors-anywhereयह एक सरल CORS प्रॉक्सी सर्वर बनाने का एक आसान तरीका है और इसका ऑनलाइन डेमो हैhttps://cors-anywhere.herokuapp.com ) यह JS कोड को उस HTML में उपयोग करने postMessageऔर आकार भेजने के लिए इंजेक्ट करता है। मूल दस्तावेज़ में iFrame। यहां तक ​​कि यह iFrame resize( iFrame के साथ संयुक्तwidth: 100% ) घटना को संभालता है और iFrame के आकार को वापस माता-पिता को पोस्ट करता है।

patchIframeHtml:

एक समारोह iFrame HTML कोड और इंजेक्षन कस्टम जावास्क्रिप्ट का उपयोग करेगा पैच करने के लिए postMessageपर माता-पिता में iFrame आकार भेजने के लिए loadऔर पर resize। यदि originपैरामीटर के लिए कोई मान है , तो <base/>उस मूल URL का उपयोग करके एक HTML तत्व को सिर पर रखा जाएगा, इस प्रकार, HTML यूआरआई जैसे /some/resource/file.extiFrame के अंदर मूल URL द्वारा ठीक से प्राप्त किया जाएगा।

function patchIframeHtml(html, origin, params = {}) {
  // Create a DOM parser
  const parser = new DOMParser();

  // Create a document parsing the HTML as "text/html"
  const doc = parser.parseFromString(html, 'text/html');

  // Create the script element that will be injected to the iFrame
  const script = doc.createElement('script');

  // Set the script code
  script.textContent = `
    window.addEventListener('load', () => {
      // Set iFrame document "height: auto" and "overlow-y: auto",
      // so to get auto height. We set "overlow-y: auto" for demontration
      // and in usage it should be "overlow-y: hidden"
      document.body.style.height = 'auto';
      document.body.style.overflowY = 'auto';

      poseResizeMessage();
    });

    window.addEventListener('resize', poseResizeMessage);

    function poseResizeMessage() {
      window.top.postMessage({
        // iframeWidth: document.body.scrollWidth,
        iframeHeight: document.body.scrollHeight,
        // pass the params as encoded URI JSON string
        // and decode them back inside iFrame
        params: JSON.parse(decodeURIComponent('${encodeURIComponent(JSON.stringify(params))}'))
      }, '*');
    }
  `;

  // Append the custom script element to the iFrame body
  doc.body.appendChild(script);

  // If we have an origin URL,
  // create a base tag using that origin
  // and prepend it to the head
  if (origin) {
    const base = doc.createElement('base');
    base.setAttribute('href', origin);

    doc.head.prepend(base);
  }

  // Return the document altered HTML that contains the injected script
  return doc.documentElement.outerHTML;
}

getIframeHtml:

एक पृष्ठ HTML पाने के लिए एक फ़ंक्शन यदि useProxyपैराम सेट किया गया है तो प्रॉक्सी का उपयोग करके कोर को बायपास करें । अतिरिक्त पैरामीटर हो सकते हैं जो postMessageआकार डेटा भेजते समय पारित हो जाएंगे ।

function getIframeHtml(url, useProxy = false, params = {}) {
  return new Promise(resolve => {
    const xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function() {
      if (xhr.readyState == XMLHttpRequest.DONE) {
        // If we use a proxy,
        // set the origin so it will be placed on a base tag inside iFrame head
        let origin = useProxy && (new URL(url)).origin;

        const patchedHtml = patchIframeHtml(xhr.responseText, origin, params);
        resolve(patchedHtml);
      }
    }

    // Use cors-anywhere proxy if useProxy is set
    xhr.open('GET', useProxy ? `https://cors-anywhere.herokuapp.com/${url}` : url, true);
    xhr.send();
  });
}

संदेश ईवेंट हैंडलर फ़ंक्शन "समान मूल iFrame आकार" के समान है

अब हम अपने कस्टम JS कोड के साथ iFrame के अंदर एक क्रॉस ओरिजिनल डोमेन लोड कर सकते हैं:

<!-- It's important that the iFrame must have a 100% width 
     for the resize event to work -->
<iframe id="iframe-cross" style="width: 100%"></iframe>

<script>
window.addEventListener('DOMContentLoaded', async () => {
  const crossDomainHtml = await getIframeHtml(
    'https://en.wikipedia.org/wiki/HTML', true /* useProxy */, { id: 'iframe-cross' }
  );

  // We use srcdoc attribute to set the iFrame HTML instead of a src URL
  document.getElementById('iframe-cross').setAttribute('srcdoc', crossDomainHtml);
});
</script>

और हम iFrame को आकार देने के लिए इसे पूरी ऊंचाई तक बिना किसी लंबवत स्क्रॉलिंग के उपयोग overflow-y: autoकरेंगे, यहां तक कि iFrame बॉडी के लिए भी इसका उपयोग कर सकते हैं ( ऐसा होना चाहिए overflow-y: hiddenकि हमें स्क्रॉलबार को आकार बदलने पर फ़्लिकर न मिले )।

आप इसे यहाँ ऑनलाइन देख सकते हैं

फिर से ध्यान दें कि यह एक हैक है और इसे टाला जाना चाहिए ; हम क्रॉस-ऑरिजिन iFrame डॉक्यूमेंट को एक्सेस नहीं कर सकते हैं और न ही किसी तरह की चीजों को इंजेक्ट कर सकते हैं।


1
धन्यवाद! बहुत बढ़िया जवाब।
फेरी

1
धन्यवाद। दुर्भाग्य cors-anywhereसे इस समय नीचे है, इसलिए आप डेमो पेज नहीं देख सकते हैं । मैं कॉपीराइट कारणों से बाहरी साइट का स्क्रीनशॉट नहीं जोड़ना चाहता। यदि लंबे समय तक नीचे रहता है तो मैं एक अन्य CORS प्रॉक्सी जोड़ूंगा।
क्रिस्टोस लिट्रास

2

एक आइफ्रेम में सामग्री के आकार को काम करने के साथ उनकी बहुत सारी जटिलताएं हैं, मुख्य रूप से सीएसएस के कारण आप उन चीजों को करने में सक्षम होते हैं जो सामग्री के आकार को मापने के तरीके को तोड़ सकते हैं।

मैंने एक पुस्तकालय लिखा था जो इन सभी बातों का ध्यान रखता है और क्रॉस डोमेन का भी काम करता है, आपको यह मददगार लग सकता है।

https://github.com/davidjbradshaw/iframe-resizer


1
ठंडा! गया कि जाँच!
5

0

मेरा समाधान GitHub और JSFiddle पर है

पहलू अनुपात धारणा के बिना उत्तरदायी iframe के लिए एक समाधान प्रस्तुत करना।

लक्ष्य है, जब आवश्यक हो, तो आइफ्रेम को दूसरे शब्दों में, जब विंडो का आकार बदला जाता है, का आकार परिवर्तन करना। यह नई विंडो का आकार पाने और परिणाम में iframe का आकार बदलने के लिए JavaScript के साथ किया जाता है।

नायब: पेज लोड होने के बाद रिसाइज फंक्शन को कॉल करना न भूलें क्योंकि पेज लोड होने के बाद विंडो अपने आप रिसाइज नहीं होती है।

कोड

index.html

<!DOCTYPE html>
<!-- Onyr for StackOverflow -->

<html>

<head> 
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
    <title>Responsive Iframe</title>
    <link rel="stylesheet" type="text/css" href="./style.css">
</head>

<body id="page_body">
    <h1>Responsive iframe</h1>

    <div id="video_wrapper">
        <iframe id="iframe" src="https://fr.wikipedia.org/wiki/Main_Page"></iframe>
    </div>

    <p> 
        Presenting a solution for responsive iframe without aspect
        ratio assumption.<br><br>
    </p>

    <script src="./main.js"></script>
</body>

</html>

style.css

html {
    height: 100%;
    max-height: 1000px;
}

body {
    background-color: #44474a;
    color: white;
    margin: 0;
    padding: 0;
}

#videoWrapper {
    position: relative;
    padding-top: 25px;
    padding-bottom: 100px;
    height: 0;
    margin: 10;
}
#iframe {
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

main.js

let videoWrapper = document.getElementById("video_wrapper");

let w;
let h;
let bodyWidth;
let bodyHeight;

// get window size and resize the iframe
function resizeIframeWrapper() {
    w = window.innerWidth;
    h = window.innerHeight;

    videoWrapper.style["width"] = `${w}px`;
    videoWrapper.style["height"] = `${h - 200}px`;
}

// call the resize function when windows is resized and after load
window.onload = resizeIframeWrapper;
window.onresize = resizeIframeWrapper;

मैंने इस पर कुछ समय बिताया। मुझे आशा है कि आप इसे पसंद करेंगे =)

संपादित करें यह शायद सबसे अच्छा सामान्य समाधान है। हालांकि, जब बहुत छोटा किया जाता है, तो इफ्रेम को उचित आकार नहीं दिया जाता है। यह आपके द्वारा उपयोग किए जा रहे iframe के लिए विशिष्ट है। इस घटना के लिए एक उचित उत्तर कोड करना संभव नहीं है जब तक कि आपके पास iframe का कोड न हो, क्योंकि आपके कोड को यह जानने का कोई तरीका नहीं है कि iframe द्वारा किस आकार को सही तरीके से प्रदर्शित किया जाना है।

@Christos Lytras द्वारा प्रस्तुत की गई केवल कुछ हैक्स ही चाल बना सकती हैं, लेकिन यह कभी भी हर ifame के लिए काम करने वाला नहीं है। सिर्फ एक विशेष स्थिति में।


कोशिश करने के लिए धन्यवाद! हालाँकि, यह अपेक्षा के अनुरूप काम नहीं कर रहा है। जब आइफ्रेम की सामग्री छोटी होती है, तब भी कंटेनर में अतिरिक्त जगह होती है। इसे देखें: jsfiddle.net/6p2suv07/3 मैंने iframe का src बदल दिया।
फेरिट

मुझे "अतिरिक्त स्थान" के साथ आपकी समस्या को समझना निश्चित नहीं है। खिड़की का न्यूनतम आकार 100 पीएक्स चौड़ाई है। आइफ्रेम कंटेनर को फिट करता है। आपके आइफ्रेम के अंदर का लेआउट मेरे नियंत्रण में नहीं है। मैंने आपके प्रश्न का उत्तर दिया। कृपया अपना संपादन करें यदि आप अधिक मदद चाहते हैं
Onyr

एक तस्वीर रखो और यह वर्णन
Onyr

iframe कंटेनर को वह सभी जगह लेता है, जो चीज देता है, जब iframe सामग्री छोटी होती है, तो उसे उस सभी स्थान की आवश्यकता नहीं होती है जो वह ले सकता है। इसलिए, कंटेनर को इफ्रेम के लिए बस पर्याप्त जगह देनी चाहिए, कोई कम नहीं और अधिक नहीं।
फेरिट

इफ्रेम की ऊंचाई के लिए, यह इसलिए है क्योंकि अंतरिक्ष की ऊंचाई मेरे उदाहरण में खिड़की द्वारा सीमित है। यही है? आपका उदाहरण आपके द्वारा उपयोग किए जाने वाले iframe के लिए विशिष्ट है, मैंने एक सामान्य उत्तर दिया, जिसे स्वीकार किया जाना चाहिए। बेशक, कोड को
मोड़ना

-1

एक बात सेट करें कि आइफ्रेम कंटेनर कुछ चौड़ाई और ऊंचाई सेट सीएसएस संपत्ति

.iframe-container{
     width:100%;
     min-height:600px;
     max-height:100vh;
}

.iframe-container iframe{
     width:100%;
     height:100%;
     object-fit:contain;
}

यदि सामग्री 600px से छोटी है तो क्या होगा?
फेरिट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.