Cara cek javascript di browser

Melayani halaman Web atau layanan yang berbeda ke browser yang berbeda biasanya merupakan ide yang buruk. Web dimaksudkan agar dapat diakses oleh semua orang, apa pun browser atau perangkat yang mereka gunakan. Ada beberapa cara untuk mengembangkan situs web Anda untuk meningkatkan dirinya sendiri secara bertahap berdasarkan ketersediaan fitur daripada dengan menargetkan browser tertentu

Tetapi browser dan standarnya tidak sempurna, dan masih ada beberapa kasus ekstrem yang memerlukan pendeteksian browser. Menggunakan agen pengguna untuk mendeteksi browser terlihat sederhana, tetapi melakukannya dengan baik sebenarnya adalah masalah yang sangat sulit. Dokumen ini akan memandu Anda dalam melakukan hal ini seakurat mungkin

Catatan. It's worth mengulangi. sangat jarang menggunakan user agent sniffing. Anda hampir selalu dapat menemukan cara yang lebih baik dan kompatibel secara lebih luas untuk menyelesaikan masalah Anda

Saat mempertimbangkan untuk menggunakan string agen pengguna untuk mendeteksi browser mana yang sedang digunakan, langkah pertama Anda adalah mencoba menghindarinya jika memungkinkan. Mulailah dengan mencoba mengidentifikasi mengapa Anda ingin melakukannya

Apakah Anda mencoba mengatasi bug tertentu di beberapa versi browser?

Lihat, atau tanyakan, di forum khusus. Anda tidak mungkin menjadi orang pertama yang menghadapi masalah ini. Juga, para ahli, atau orang-orang dengan sudut pandang lain, dapat memberi Anda ide untuk mengatasi bug tersebut. Jika masalah tampaknya tidak biasa, sebaiknya periksa apakah bug ini telah dilaporkan ke vendor browser melalui sistem pelacakan bug mereka (Mozilla; WebKit; Blink; Opera). Pembuat browser benar-benar memperhatikan laporan bug, dan analisisnya mungkin memberi petunjuk tentang solusi lain untuk bug tersebut

Apakah Anda mencoba memeriksa keberadaan fitur tertentu?

Situs Anda perlu menggunakan fitur Web tertentu yang belum didukung oleh beberapa browser, dan Anda ingin mengirim pengguna tersebut ke situs Web lama dengan lebih sedikit fitur tetapi Anda tahu akan berfungsi. Ini adalah alasan terburuk untuk menggunakan deteksi agen pengguna karena kemungkinan besar pada akhirnya semua browser lain akan menyusul. Selain itu, tidak praktis untuk menguji setiap browser yang kurang populer dan menguji fitur Web tersebut. Anda seharusnya tidak pernah mengendus agen pengguna. Selalu ada alternatif melakukan deteksi fitur sebagai gantinya

Apakah Anda ingin memberikan HTML yang berbeda tergantung pada browser mana yang digunakan?

Ini biasanya merupakan praktik yang buruk, tetapi ada beberapa kasus di mana hal ini diperlukan. Dalam kasus ini, pertama-tama Anda harus menganalisis situasi Anda untuk memastikan bahwa itu benar-benar diperlukan. Bisakah Anda mencegahnya dengan menambahkan beberapa elemen non-semantik <div> atau <span>? . Juga, pikirkan kembali desain Anda. dapatkah Anda menggunakan peningkatan progresif atau tata letak yang lancar untuk membantu menghilangkan kebutuhan untuk melakukan ini?

Jika Anda ingin menghindari penggunaan deteksi agen pengguna, Anda memiliki opsi

Deteksi fitur

Deteksi fitur adalah saat Anda tidak mencoba mencari tahu browser mana yang merender halaman Anda, tetapi sebaliknya, Anda memeriksa untuk melihat apakah fitur spesifik yang Anda perlukan tersedia. Jika tidak, Anda menggunakan fallback. Dalam kasus yang jarang terjadi ketika perilaku berbeda di antara browser, alih-alih memeriksa string agen pengguna, Anda sebaiknya mengimplementasikan pengujian untuk mendeteksi bagaimana browser mengimplementasikan API dan menentukan cara menggunakannya dari situ. Contoh deteksi fitur adalah sebagai berikut. Pada tahun 2017, dukungan tampilan belakang eksperimental yang tidak ditandai Chrome dalam ekspresi reguler, tetapi tidak ada browser lain yang mendukungnya. Jadi, Anda mungkin berpikir untuk melakukan ini

// This code snippet splits a string in a special notation
let splitUpString;
if (navigator.userAgent.includes("Chrome")) {
  // YES! The user is suspected to support look-behind regexps
  // DO NOT USE /(?<=[A-Z])/. It will cause a syntax error in
  // browsers that do not support look-behind expressions
  // because all browsers parse the entire script, including
  // sections of the code that are never executed.
  const camelCaseExpression = new RegExp("(?<=[A-Z])");
  splitUpString = (str) => String(str).split(camelCaseExpression);
} else {
  // This fallback code is much less performant, but works
  splitUpString = (str) => str.replace(/[A-Z]/g, "z$1").split(/z(?=[A-Z])/g);
}

console.log(splitUpString("fooBare")); // ["fooB", "are"]
console.log(splitUpString("jQWhy")); // ["jQ", "W", "hy"]

Kode di atas akan membuat beberapa asumsi yang salah. Pertama, diasumsikan bahwa semua string agen pengguna yang menyertakan substring "Chrome" adalah Chrome. String UA terkenal menyesatkan. Kemudian, diasumsikan bahwa fitur lookbehind akan selalu tersedia jika browsernya adalah Chrome. Agen tersebut mungkin Chrome versi lama, dari sebelum dukungan ditambahkan, atau (karena fitur tersebut masih dalam tahap percobaan) bisa jadi versi Chrome yang lebih baru yang menghapusnya. Yang terpenting, diasumsikan tidak ada browser lain yang mendukung fitur tersebut. Dukungan dapat ditambahkan ke browser lain kapan saja, tetapi kode ini akan terus memilih jalur yang lebih rendah

Masalah seperti ini dapat dihindari dengan menguji dukungan fitur itu sendiri

let isLookBehindSupported = false;

try {
  new RegExp("(?<=)");
  isLookBehindSupported = true;
} catch (err) {
  // If the agent doesn't support look behinds, the attempted
  // creation of a RegExp object using that syntax throws and
  // isLookBehindSupported remains false.
}

const splitUpString = isLookBehindSupported
  ? (str) => String(str).split(new RegExp("(?<=[A-Z])"))
  : (str) => str.replace(/[A-Z]/g, "z$1").split(/z(?=[A-Z])/g);
_

Seperti yang ditunjukkan oleh kode di atas, selalu ada cara untuk menguji dukungan browser tanpa mengendus agen pengguna. Tidak pernah ada alasan untuk memeriksa string agen pengguna untuk ini

Terakhir, cuplikan kode di atas menimbulkan masalah kritis dengan pengkodean lintas-browser yang harus selalu diperhitungkan. Jangan sengaja menggunakan API yang Anda uji di browser yang tidak didukung. Ini mungkin terdengar jelas dan sederhana, tetapi terkadang tidak. Misalnya, dalam cuplikan kode di atas, menggunakan lookbehind dalam notasi regexp pendek (misalnya, /reg/igm) akan menyebabkan kesalahan parser di browser yang tidak didukung. Jadi, dalam contoh di atas, Anda akan menggunakan new RegExp("(?<=look_behind_stuff)");

Peningkatan progresif

Teknik desain ini melibatkan pengembangan situs Web Anda dalam 'lapisan', menggunakan pendekatan dari bawah ke atas, dimulai dengan lapisan yang lebih sederhana dan meningkatkan kemampuan situs dalam lapisan yang berurutan, masing-masing menggunakan lebih banyak fitur.

Degradasi anggun

Ini adalah pendekatan top-down di mana Anda membangun situs sebaik mungkin menggunakan semua fitur yang Anda inginkan, lalu men-tweaknya agar berfungsi di browser lama. Ini bisa lebih sulit dilakukan, dan kurang efektif, daripada peningkatan progresif, tetapi mungkin berguna dalam beberapa kasus

Deteksi perangkat seluler

Dapat dikatakan bahwa penggunaan dan penyalahgunaan yang paling umum dari mengendus agen pengguna adalah untuk mendeteksi apakah perangkat tersebut adalah perangkat seluler. Namun, orang terlalu sering mengabaikan apa yang sebenarnya mereka cari. Orang-orang menggunakan pengendusan agen pengguna untuk mendeteksi apakah perangkat pengguna ramah sentuhan dan memiliki layar kecil sehingga mereka dapat mengoptimalkan situs web mereka sesuai dengan itu. Meskipun pengendapan agen pengguna terkadang dapat mendeteksi hal ini, tidak semua perangkat sama. beberapa perangkat seluler memiliki ukuran layar yang besar, beberapa desktop memiliki layar sentuh kecil, beberapa orang menggunakan smart TV yang merupakan ballgame yang sama sekali berbeda, dan beberapa orang dapat secara dinamis mengubah lebar dan tinggi layar mereka dengan membalik tablet mereka ke samping. Jadi, mengendus agen pengguna jelas bukan cara yang tepat. Untungnya, ada banyak alternatif yang lebih baik. Gunakan Navigator. maxTouchPoints untuk mendeteksi jika perangkat pengguna memiliki layar sentuh. Kemudian, default kembali untuk memeriksa layar agen pengguna hanya jika (. ("maxTouchPoints" di navigator)) { /*Kode di sini*/}. Dengan menggunakan informasi apakah perangkat memiliki layar sentuh, jangan ubah seluruh tata letak situs web hanya untuk perangkat sentuh. Anda hanya akan menciptakan lebih banyak pekerjaan dan pemeliharaan untuk diri Anda sendiri. Sebaliknya, tambahkan kenyamanan sentuhan seperti tombol yang lebih besar dan lebih mudah diklik (Anda dapat melakukannya menggunakan CSS dengan memperbesar ukuran font). Berikut adalah contoh kode yang meningkatkan padding #exampleButton menjadi 1em di perangkat seluler

let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}

Sedangkan untuk ukuran layar, gunakan window. innerWidth dan jendela. addEventListener("resize", () => { /*refresh hal-hal yang bergantung pada ukuran layar*/ }). Apa yang ingin Anda lakukan untuk ukuran layar bukanlah memotong informasi pada layar yang lebih kecil. Itu hanya akan mengganggu orang karena akan memaksa mereka menggunakan versi desktop. Sebaliknya, cobalah untuk memiliki lebih sedikit kolom informasi di halaman yang lebih panjang di layar yang lebih kecil sambil memiliki lebih banyak kolom dengan halaman yang lebih pendek di ukuran layar yang lebih besar. Efek ini dapat dengan mudah dicapai dengan menggunakan kotak fleksibel CSS, terkadang dengan pelampung sebagai cadangan sebagian

Coba juga untuk memindahkan informasi yang kurang relevan/penting ke bagian bawah dan kelompokkan konten halaman secara bermakna. Meskipun di luar topik, mungkin contoh mendetail berikut dapat memberi Anda wawasan dan ide yang membujuk Anda untuk tidak mengendus agen pengguna. Mari kita bayangkan sebuah halaman yang terdiri dari kotak-kotak informasi; . Setiap kotak memiliki gambar, ikhtisar, dan fakta sejarah yang menyenangkan. Gambar disimpan dalam ukuran maksimum yang masuk akal bahkan pada layar besar. Untuk tujuan mengelompokkan konten secara bermakna, semua kotak kucing dipisahkan dari semua kotak anjing sedemikian rupa sehingga kotak kucing dan anjing tidak bercampur menjadi satu. Pada layar besar, menghemat ruang untuk memiliki banyak kolom untuk mengurangi ruang yang terbuang ke kiri dan ke kanan gambar. Kotak dapat dipisahkan menjadi beberapa kolom melalui dua metode yang sama adilnya. Mulai saat ini, kita akan berasumsi bahwa semua kotak anjing berada di bagian atas kode sumber, semua kotak kucing berada di bagian bawah kode sumber, dan semua kotak ini memiliki elemen induk yang sama. Ada satu contoh kotak anjing tepat di atas kotak kucing, tentu saja. Metode pertama menggunakan Flexbox horizontal untuk mengelompokkan konten sehingga saat halaman ditampilkan ke pengguna akhir, semua kotak anjing berada di bagian atas halaman dan semua kotak kucing berada di bawah halaman. Metode kedua menggunakan tata letak Kolom dan membenci semua anjing di sebelah kiri dan semua kucing di sebelah kanan. Hanya dalam skenario khusus ini, sebaiknya tidak memberikan cadangan untuk kotak fleksibel/multikolom, yang menghasilkan satu kolom kotak yang sangat lebar di browser lama. Pertimbangkan juga hal-hal berikut ini. Jika lebih banyak orang yang mengunjungi halaman web untuk melihat kucing, sebaiknya tempatkan semua kucing lebih tinggi di kode sumber daripada anjing sehingga lebih banyak orang dapat menemukan apa yang mereka cari dengan lebih cepat di layar yang lebih kecil tempat konten diciutkan

Next, always make your code dynamic. The user can flip their mobile device on its side, changing the width and height of the page. Or, there might be some weird flip-phone-like device thing in the future where flipping it out extends the screen. Do not be the developer having a headache over how to deal with the flip-phone-like device thing. Never be satisfied with your webpage until you can open up the dev tools side panel and resize the screen while the webpage looks smooth, fluid, and dynamically resized. The simplest way to do this is to separate all the code that moves content around based on screen size to a single function that is called when the page is loaded and at each resize event thereafter. If there is a lot calculated by this layout function before it determines the new layout of the page, then consider debouncing the event listener such that it is not called as often. Also note that there is a huge difference between the media queries (max-width: 25em), not all and (min-width: 25em), and (max-width: 24.99em): (max-width: 25em) excludes (max-width: 25em), whereas not all and (min-width: 25em) includes (max-width: 25em). (max-width: 24.99em) is a poor man's version of not all and (min-width: 25em): do not use (max-width: 24.99em) because the layout might break on very high font sizes on very high definition devices in the future. Always be very deliberate about choosing the right media query and choosing the right >=, <=, >, or < in any corresponding JavaScript because it is very easy to get these mixed up, resulting in the website looking wonky right at the screen size where the layout changes. Thus, thoroughly test the website at the exact widths/heights where layout changes occur to ensure that the layout changes occur properly.

Setelah meninjau semua alternatif yang lebih baik di atas untuk mengendus agen pengguna, masih ada beberapa kasus potensial di mana mengendus agen pengguna sesuai dan dibenarkan

Salah satu kasus tersebut menggunakan user agent sniffing sebagai fallback saat mendeteksi jika perangkat memiliki layar sentuh. Lihat bagian untuk informasi lebih lanjut

Kasus serupa lainnya adalah untuk memperbaiki bug di browser yang tidak diperbarui secara otomatis. Internet Explorer (di Windows) dan Webkit (di iOS) adalah dua contoh sempurna. Sebelum versi 9, Internet Explorer memiliki masalah dengan rendering bug, bug CSS, bug API, dan sebagainya. Namun, sebelum versi 9, Internet Explorer sangat mudah dideteksi berdasarkan fitur khusus browser yang tersedia. Webkit sedikit lebih buruk karena Apple memaksa semua browser di iOS untuk menggunakan Webkit secara internal, sehingga pengguna tidak memiliki cara untuk mendapatkan browser yang lebih baik dan lebih diperbarui di perangkat yang lebih lama. Sebagian besar bug dapat dideteksi, tetapi beberapa bug membutuhkan lebih banyak upaya untuk mendeteksi daripada yang lain. Dalam kasus seperti itu, mungkin bermanfaat untuk menggunakan pengendusan agen pengguna untuk menghemat kinerja. Misalnya, Webkit 6 memiliki bug di mana ketika orientasi perangkat berubah, browser mungkin tidak memecat pendengar MediaQueryList ketika seharusnya. Untuk mengatasi bug ini, perhatikan kode di bawah ini

const UA = navigator.userAgent;
const isWebkit =
  /\b(iPad|iPhone|iPod)\b/.test(UA) &&
  /WebKit/.test(UA) &&
  !/Edge/.test(UA) &&
  !window.MSStream;

let mediaQueryUpdated = true;
const mqL = [];

function whenMediaChanges() {
  mediaQueryUpdated = true;
}

const listenToMediaQuery = isWebkit
  ? (mQ, f) => {
      if (/height|width/.test(mQ.media)) {
        mqL.push([mQ, f]);
      }
      mQ.addListener(f);
      mQ.addListener(whenMediaChanges);
    }
  : () => {};

const destroyMediaQuery = isWebkit
  ? (mQ) => {
      for (let i = 0; i < mqL.length; i++) {
        if (mqL[i][0] === mQ) {
          mqL.splice(i, 1);
        }
      }
      mQ.removeListener(whenMediaChanges);
    }
  : listenToMediaQuery;

let orientationChanged = false;
addEventListener(
  "orientationchange",
  () => {
    orientationChanged = true;
  },
  PASSIVE_LISTENER_OPTION
);

addEventListener("resize", () =>
  setTimeout(() => {
    if (orientationChanged && !mediaQueryUpdated) {
      for (let i = 0; i < mqL.length; i++) {
        mqL[i][1](mqL[i][0]);
      }
    }
    mediaQueryUpdated = orientationChanged = false;
  }, 0)
);

Karena tidak ada keseragaman bagian yang berbeda dari string agen pengguna, ini adalah bagian yang rumit

Ketika orang mengatakan mereka ingin "deteksi browser", sering kali mereka benar-benar menginginkan "deteksi mesin render". Apakah Anda benar-benar ingin mendeteksi Firefox, bukan SeaMonkey, atau Chrome sebagai lawan Chromium?

Sebagian besar browser menetapkan nama dan versi dalam format BrowserName/VersionNumber, dengan pengecualian Internet Explorer. Namun karena nama bukanlah satu-satunya informasi dalam string agen pengguna yang ada dalam format tersebut, Anda tidak dapat menemukan nama browser, Anda hanya dapat memeriksa apakah nama yang Anda cari. Tetapi perhatikan bahwa beberapa browser berbohong. Chrome misalnya melaporkan sebagai Chrome dan Safari. Jadi untuk mendeteksi Safari Anda harus memeriksa string Safari dan tidak adanya string Chrome, Chromium sering melaporkan dirinya sebagai Chrome juga atau Seamonkey terkadang melaporkan dirinya sebagai Firefox

Perhatikan juga untuk tidak menggunakan ekspresi reguler sederhana pada BrowserName, agen pengguna juga berisi string di luar sintaks Kata Kunci/Nilai. Safari & Chrome berisi string 'like Gecko', misalnya

EngineMust containMust not containFirefox
let isLookBehindSupported = false;

try {
  new RegExp("(?<=)");
  isLookBehindSupported = true;
} catch (err) {
  // If the agent doesn't support look behinds, the attempted
  // creation of a RegExp object using that syntax throws and
  // isLookBehindSupported remains false.
}

const splitUpString = isLookBehindSupported
  ? (str) => String(str).split(new RegExp("(?<=[A-Z])"))
  : (str) => str.replace(/[A-Z]/g, "z$1").split(/z(?=[A-Z])/g);
6
let isLookBehindSupported = false;

try {
  new RegExp("(?<=)");
  isLookBehindSupported = true;
} catch (err) {
  // If the agent doesn't support look behinds, the attempted
  // creation of a RegExp object using that syntax throws and
  // isLookBehindSupported remains false.
}

const splitUpString = isLookBehindSupported
  ? (str) => String(str).split(new RegExp("(?<=[A-Z])"))
  : (str) => str.replace(/[A-Z]/g, "z$1").split(/z(?=[A-Z])/g);
7Seamonkey
let isLookBehindSupported = false;

try {
  new RegExp("(?<=)");
  isLookBehindSupported = true;
} catch (err) {
  // If the agent doesn't support look behinds, the attempted
  // creation of a RegExp object using that syntax throws and
  // isLookBehindSupported remains false.
}

const splitUpString = isLookBehindSupported
  ? (str) => String(str).split(new RegExp("(?<=[A-Z])"))
  : (str) => str.replace(/[A-Z]/g, "z$1").split(/z(?=[A-Z])/g);
7Chrome
let isLookBehindSupported = false;

try {
  new RegExp("(?<=)");
  isLookBehindSupported = true;
} catch (err) {
  // If the agent doesn't support look behinds, the attempted
  // creation of a RegExp object using that syntax throws and
  // isLookBehindSupported remains false.
}

const splitUpString = isLookBehindSupported
  ? (str) => String(str).split(new RegExp("(?<=[A-Z])"))
  : (str) => str.replace(/[A-Z]/g, "z$1").split(/z(?=[A-Z])/g);
9
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
0 or
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
1Chromium
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
0Safari
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
3
let isLookBehindSupported = false;

try {
  new RegExp("(?<=)");
  isLookBehindSupported = true;
} catch (err) {
  // If the agent doesn't support look behinds, the attempted
  // creation of a RegExp object using that syntax throws and
  // isLookBehindSupported remains false.
}

const splitUpString = isLookBehindSupported
  ? (str) => String(str).split(new RegExp("(?<=[A-Z])"))
  : (str) => str.replace(/[A-Z]/g, "z$1").split(/z(?=[A-Z])/g);
9 or
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
0Opera 15+ (Blink-based engine)
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
6Opera 12- (Presto-based engine)
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
7Internet Explorer 10-
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
8Internet Explorer 11
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
9

[1] Safari memberikan dua nomor versi. satu teknis dalam token

let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
_3, dan satu ramah pengguna dalam token
const UA = navigator.userAgent;
const isWebkit =
  /\b(iPad|iPhone|iPod)\b/.test(UA) &&
  /WebKit/.test(UA) &&
  !/Edge/.test(UA) &&
  !window.MSStream;

let mediaQueryUpdated = true;
const mqL = [];

function whenMediaChanges() {
  mediaQueryUpdated = true;
}

const listenToMediaQuery = isWebkit
  ? (mQ, f) => {
      if (/height|width/.test(mQ.media)) {
        mqL.push([mQ, f]);
      }
      mQ.addListener(f);
      mQ.addListener(whenMediaChanges);
    }
  : () => {};

const destroyMediaQuery = isWebkit
  ? (mQ) => {
      for (let i = 0; i < mqL.length; i++) {
        if (mqL[i][0] === mQ) {
          mqL.splice(i, 1);
        }
      }
      mQ.removeListener(whenMediaChanges);
    }
  : listenToMediaQuery;

let orientationChanged = false;
addEventListener(
  "orientationchange",
  () => {
    orientationChanged = true;
  },
  PASSIVE_LISTENER_OPTION
);

addEventListener("resize", () =>
  setTimeout(() => {
    if (orientationChanged && !mediaQueryUpdated) {
      for (let i = 0; i < mqL.length; i++) {
        mqL[i][1](mqL[i][0]);
      }
    }
    mediaQueryUpdated = orientationChanged = false;
  }, 0)
);
1

Tentu saja, sama sekali tidak ada jaminan bahwa browser lain tidak akan membajak beberapa hal ini (seperti Chrome membajak string Safari di masa lalu). Itu sebabnya deteksi browser menggunakan string agen pengguna tidak dapat diandalkan dan harus dilakukan hanya dengan pemeriksaan nomor versi (kemungkinan pembajakan versi sebelumnya lebih kecil)

Versi browser seringkali, tetapi tidak selalu, dimasukkan ke dalam bagian nilai dari token BrowserName/VersionNumber di User Agent String. Ini tentu saja tidak berlaku untuk Internet Explorer (yang menempatkan nomor versi tepat setelah token MSIE), dan untuk Opera setelah versi 10, yang telah menambahkan token Versi/VersionNumber

Sekali lagi, pastikan untuk mengambil token yang tepat untuk browser yang Anda cari, karena tidak ada jaminan bahwa yang lain akan berisi nomor yang valid

Seperti yang terlihat sebelumnya, dalam banyak kasus, mencari mesin rendering adalah cara yang lebih baik. Ini akan membantu untuk tidak mengecualikan browser yang kurang dikenal. Browser yang berbagi mesin rendering umum akan menampilkan halaman dengan cara yang sama. seringkali merupakan asumsi yang adil bahwa apa yang akan berhasil di satu akan berhasil di yang lain

Ada lima mesin rendering utama. Trident, Gecko, Presto, Blink, dan WebKit. Karena mengendus nama mesin rendering adalah hal biasa, banyak agen pengguna menambahkan nama rendering lain untuk memicu deteksi. Oleh karena itu, penting untuk diperhatikan agar tidak memicu positif palsu saat mendeteksi mesin rendering

EngineHarus berisiCommentGecko
const UA = navigator.userAgent;
const isWebkit =
  /\b(iPad|iPhone|iPod)\b/.test(UA) &&
  /WebKit/.test(UA) &&
  !/Edge/.test(UA) &&
  !window.MSStream;

let mediaQueryUpdated = true;
const mqL = [];

function whenMediaChanges() {
  mediaQueryUpdated = true;
}

const listenToMediaQuery = isWebkit
  ? (mQ, f) => {
      if (/height|width/.test(mQ.media)) {
        mqL.push([mQ, f]);
      }
      mQ.addListener(f);
      mQ.addListener(whenMediaChanges);
    }
  : () => {};

const destroyMediaQuery = isWebkit
  ? (mQ) => {
      for (let i = 0; i < mqL.length; i++) {
        if (mqL[i][0] === mQ) {
          mqL.splice(i, 1);
        }
      }
      mQ.removeListener(whenMediaChanges);
    }
  : listenToMediaQuery;

let orientationChanged = false;
addEventListener(
  "orientationchange",
  () => {
    orientationChanged = true;
  },
  PASSIVE_LISTENER_OPTION
);

addEventListener("resize", () =>
  setTimeout(() => {
    if (orientationChanged && !mediaQueryUpdated) {
      for (let i = 0; i < mqL.length; i++) {
        mqL[i][1](mqL[i][0]);
      }
    }
    mediaQueryUpdated = orientationChanged = false;
  }, 0)
);
2WebKit
const UA = navigator.userAgent;
const isWebkit =
  /\b(iPad|iPhone|iPod)\b/.test(UA) &&
  /WebKit/.test(UA) &&
  !/Edge/.test(UA) &&
  !window.MSStream;

let mediaQueryUpdated = true;
const mqL = [];

function whenMediaChanges() {
  mediaQueryUpdated = true;
}

const listenToMediaQuery = isWebkit
  ? (mQ, f) => {
      if (/height|width/.test(mQ.media)) {
        mqL.push([mQ, f]);
      }
      mQ.addListener(f);
      mQ.addListener(whenMediaChanges);
    }
  : () => {};

const destroyMediaQuery = isWebkit
  ? (mQ) => {
      for (let i = 0; i < mqL.length; i++) {
        if (mqL[i][0] === mQ) {
          mqL.splice(i, 1);
        }
      }
      mQ.removeListener(whenMediaChanges);
    }
  : listenToMediaQuery;

let orientationChanged = false;
addEventListener(
  "orientationchange",
  () => {
    orientationChanged = true;
  },
  PASSIVE_LISTENER_OPTION
);

addEventListener("resize", () =>
  setTimeout(() => {
    if (orientationChanged && !mediaQueryUpdated) {
      for (let i = 0; i < mqL.length; i++) {
        mqL[i][1](mqL[i][0]);
      }
    }
    mediaQueryUpdated = orientationChanged = false;
  }, 0)
);
3Perhatikan, browser WebKit menambahkan string 'like Gecko' yang dapat memicu false positive untuk Gecko jika pendeteksiannya tidak hati-hati. Presto
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
_7Catatan. Presto tidak lagi digunakan di build browser Opera >= versi 15 (lihat 'Blink')Trident
const UA = navigator.userAgent;
const isWebkit =
  /\b(iPad|iPhone|iPod)\b/.test(UA) &&
  /WebKit/.test(UA) &&
  !/Edge/.test(UA) &&
  !window.MSStream;

let mediaQueryUpdated = true;
const mqL = [];

function whenMediaChanges() {
  mediaQueryUpdated = true;
}

const listenToMediaQuery = isWebkit
  ? (mQ, f) => {
      if (/height|width/.test(mQ.media)) {
        mqL.push([mQ, f]);
      }
      mQ.addListener(f);
      mQ.addListener(whenMediaChanges);
    }
  : () => {};

const destroyMediaQuery = isWebkit
  ? (mQ) => {
      for (let i = 0; i < mqL.length; i++) {
        if (mqL[i][0] === mQ) {
          mqL.splice(i, 1);
        }
      }
      mQ.removeListener(whenMediaChanges);
    }
  : listenToMediaQuery;

let orientationChanged = false;
addEventListener(
  "orientationchange",
  () => {
    orientationChanged = true;
  },
  PASSIVE_LISTENER_OPTION
);

addEventListener("resize", () =>
  setTimeout(() => {
    if (orientationChanged && !mediaQueryUpdated) {
      for (let i = 0; i < mqL.length; i++) {
        mqL[i][1](mqL[i][0]);
      }
    }
    mediaQueryUpdated = orientationChanged = false;
  }, 0)
);
5Internet Explorer taruh token ini di bagian komentar User Agent StringEdgeHTML
const UA = navigator.userAgent;
const isWebkit =
  /\b(iPad|iPhone|iPod)\b/.test(UA) &&
  /WebKit/.test(UA) &&
  !/Edge/.test(UA) &&
  !window.MSStream;

let mediaQueryUpdated = true;
const mqL = [];

function whenMediaChanges() {
  mediaQueryUpdated = true;
}

const listenToMediaQuery = isWebkit
  ? (mQ, f) => {
      if (/height|width/.test(mQ.media)) {
        mqL.push([mQ, f]);
      }
      mQ.addListener(f);
      mQ.addListener(whenMediaChanges);
    }
  : () => {};

const destroyMediaQuery = isWebkit
  ? (mQ) => {
      for (let i = 0; i < mqL.length; i++) {
        if (mqL[i][0] === mQ) {
          mqL.splice(i, 1);
        }
      }
      mQ.removeListener(whenMediaChanges);
    }
  : listenToMediaQuery;

let orientationChanged = false;
addEventListener(
  "orientationchange",
  () => {
    orientationChanged = true;
  },
  PASSIVE_LISTENER_OPTION
);

addEventListener("resize", () =>
  setTimeout(() => {
    if (orientationChanged && !mediaQueryUpdated) {
      for (let i = 0; i < mqL.length; i++) {
        mqL[i][1](mqL[i][0]);
      }
    }
    mediaQueryUpdated = orientationChanged = false;
  }, 0)
);
6The non-Chromium Edge menempatkan versi mesinnya setelah Edge/ token, bukan aplikasi . Catatan. EdgeHTML tidak lagi digunakan di build browser Edge >= versi 79 (lihat 'Blink'). Berkedip
let isLookBehindSupported = false;

try {
  new RegExp("(?<=)");
  isLookBehindSupported = true;
} catch (err) {
  // If the agent doesn't support look behinds, the attempted
  // creation of a RegExp object using that syntax throws and
  // isLookBehindSupported remains false.
}

const splitUpString = isLookBehindSupported
  ? (str) => String(str).split(new RegExp("(?<=[A-Z])"))
  : (str) => str.replace(/[A-Z]/g, "z$1").split(/z(?=[A-Z])/g);
_9

Sebagian besar mesin rendering menempatkan nomor versi di token RenderingEngine/VersionNumber, dengan pengecualian Gecko. Gecko menempatkan nomor versi Gecko di bagian komentar Agen Pengguna setelah string

const UA = navigator.userAgent;
const isWebkit =
  /\b(iPad|iPhone|iPod)\b/.test(UA) &&
  /WebKit/.test(UA) &&
  !/Edge/.test(UA) &&
  !window.MSStream;

let mediaQueryUpdated = true;
const mqL = [];

function whenMediaChanges() {
  mediaQueryUpdated = true;
}

const listenToMediaQuery = isWebkit
  ? (mQ, f) => {
      if (/height|width/.test(mQ.media)) {
        mqL.push([mQ, f]);
      }
      mQ.addListener(f);
      mQ.addListener(whenMediaChanges);
    }
  : () => {};

const destroyMediaQuery = isWebkit
  ? (mQ) => {
      for (let i = 0; i < mqL.length; i++) {
        if (mqL[i][0] === mQ) {
          mqL.splice(i, 1);
        }
      }
      mQ.removeListener(whenMediaChanges);
    }
  : listenToMediaQuery;

let orientationChanged = false;
addEventListener(
  "orientationchange",
  () => {
    orientationChanged = true;
  },
  PASSIVE_LISTENER_OPTION
);

addEventListener("resize", () =>
  setTimeout(() => {
    if (orientationChanged && !mediaQueryUpdated) {
      for (let i = 0; i < mqL.length; i++) {
        mqL[i][1](mqL[i][0]);
      }
    }
    mediaQueryUpdated = orientationChanged = false;
  }, 0)
);
8. Dari Gecko 14 untuk versi seluler dan Gecko 17 untuk versi desktop, itu juga menempatkan nilai ini dalam token
const UA = navigator.userAgent;
const isWebkit =
  /\b(iPad|iPhone|iPod)\b/.test(UA) &&
  /WebKit/.test(UA) &&
  !/Edge/.test(UA) &&
  !window.MSStream;

let mediaQueryUpdated = true;
const mqL = [];

function whenMediaChanges() {
  mediaQueryUpdated = true;
}

const listenToMediaQuery = isWebkit
  ? (mQ, f) => {
      if (/height|width/.test(mQ.media)) {
        mqL.push([mQ, f]);
      }
      mQ.addListener(f);
      mQ.addListener(whenMediaChanges);
    }
  : () => {};

const destroyMediaQuery = isWebkit
  ? (mQ) => {
      for (let i = 0; i < mqL.length; i++) {
        if (mqL[i][0] === mQ) {
          mqL.splice(i, 1);
        }
      }
      mQ.removeListener(whenMediaChanges);
    }
  : listenToMediaQuery;

let orientationChanged = false;
addEventListener(
  "orientationchange",
  () => {
    orientationChanged = true;
  },
  PASSIVE_LISTENER_OPTION
);

addEventListener("resize", () =>
  setTimeout(() => {
    if (orientationChanged && !mediaQueryUpdated) {
      for (let i = 0; i < mqL.length; i++) {
        mqL[i][1](mqL[i][0]);
      }
    }
    mediaQueryUpdated = orientationChanged = false;
  }, 0)
);
9 (versi sebelumnya mencantumkan tanggal pembuatan, kemudian tanggal tetap yang disebut GeckoTrail)

Sistem Operasi diberikan di sebagian besar string Agen Pengguna (walaupun bukan platform yang berfokus pada web seperti Firefox OS), tetapi formatnya sangat bervariasi. Ini adalah string tetap antara dua titik koma, di bagian komentar Agen Pengguna. String ini khusus untuk setiap browser. Mereka menunjukkan OS, tetapi juga sering kali versi dan informasinya pada perangkat keras yang diandalkan (32 atau 64 bit, atau Intel/PPC untuk Mac)

Seperti dalam semua kasus, string ini dapat berubah di masa mendatang, seseorang harus menggunakannya hanya dalam hubungannya dengan deteksi browser yang sudah dirilis. Survei teknologi harus dilakukan untuk mengadaptasi skrip saat versi browser baru keluar

Alasan paling umum untuk melakukan user agent sniffing adalah untuk menentukan jenis perangkat yang digunakan browser. Tujuannya adalah untuk menyajikan HTML yang berbeda ke jenis perangkat yang berbeda

  • Jangan pernah berasumsi bahwa browser atau mesin rendering hanya berjalan di satu jenis perangkat. Terutama jangan membuat default yang berbeda untuk browser atau mesin rendering yang berbeda
  • Jangan pernah menggunakan token OS untuk menentukan apakah browser ada di ponsel, tablet, atau desktop. OS dapat berjalan di lebih dari satu jenis (misalnya, Android berjalan di tablet dan juga ponsel)

Tabel berikut meringkas cara vendor browser umum menunjukkan bahwa browser mereka berjalan di perangkat seluler

BrowserRuleExampleMozilla (Gecko, Firefox)<div>0 atau <div>1 di dalam komentar. <div>2Berbasis WebKit (Android, Safari)<div>3 menandai komentar. <div>4Berbasis kedipan (Chromium, Google Chrome, Opera 15+, Edge di Android)<div>3 token di luar komentar. <div>6Berbasis Presto (Opera 12-)<div>7 token di dalam komentar. <div>8Internet Explorer<div>9 token di komentar. <span>0Edge pada Windows 10 Mobile<span>1 dan <span>2 token di luar komentar. <span>3

Singkatnya, kami sarankan untuk mencari string <span>4 di mana pun di Agen Pengguna untuk mendeteksi perangkat seluler

Catatan. Jika perangkat cukup besar sehingga tidak ditandai dengan <span>4, Anda harus menayangkan situs desktop Anda (yang, sebagai praktik terbaik, tetap harus mendukung input sentuh, karena semakin banyak mesin desktop yang muncul dengan layar sentuh)

Bagaimana cara menguji JavaScript di Chrome?

Buka Chrome, tekan Ctrl+Shift+j dan ini akan membuka konsol JavaScript tempat Anda dapat menulis dan menguji kode Anda. Simpan jawaban ini.

Bagaimana cara menguji JavaScript di konsol browser?

Untuk memasukkan pernyataan dan ekspresi JavaScript secara interaktif di Konsol. Klik kanan di halaman web lalu pilih Periksa . DevTools terbuka. Atau, tekan Ctrl + Shift + J (Windows, Linux) atau Command + Option + J (macOS), untuk langsung membuka konsol DevTools.

Bagaimana cara memeriksa apakah js berfungsi?

buka Alat
lalu Opsi Internet
pilih tab Keamanan
tekan tombol Tingkat Kustom
gulir ke bawah ke Scripting
aktifkan Skrip Aktif

Bisakah Anda melihat JavaScript di inspeksi?

Klik kanan pada laman web mana pun, klik Periksa, dan Anda akan melihat jeroan situs tersebut. kode sumbernya, gambar dan CSS yang membentuk desainnya, font dan ikon yang digunakannya, kode Javascript yang menggerakkan animasi, dan banyak lagi.