tyoshikawa1106のブログ

- Force.com Developer Blog -

SFDC:WebサイトへのForce.comサイトページの埋め込みを試してみました

SalesforceのVisualforceページを外部に公開したい場合はForce.comサイトを仕組みを使用します。ページ全体をForce.comサイトで開発できるときは話が簡単ですが、既存のWebサイト内にある入力フォームだけをForce.comサイトで構築したい場合は少し検討が必要な部分があるので今回その部分について確認してみました。

JP:Sites - developer.force.com

はじめに

Salesforceと関係無いWebサイトにForce.comサイトページを表示するにはiframeで表示させます。ですが、ただiframeで表示するだけだとモバイル端末でアクセスした際にレイアウトが崩れてしまいます。


社外の様々な人たちがアクセスする外部サイトの場合は画面サイズに合わせてレイアウトが調整されるレスポンシブ対応を考慮する必要があります。


※iframeのレスポンシブ対応についてはこちらのサイトがとても参考になりました。

iframeのレスポンシブ対応はもの凄く簡単 | ウェブデザインスクールをお探しならWEB塾 超現場主義|東京(上野)・長野・浜松・札幌

iframeのレスポンシブ対応についての動作検証

まずは通常のWebサイトだけでiframeのレスポンシブ対応がうまくいくかを確認してみます。Webサイトの立ち上げはHerokuとLightning Design SystemのGetting Startedの手順で用意しました。

f:id:tyoshikawa1106:20181027180537p:plain

Heroku - Lightning Design System

Step 1: Initialize your project

ディレクトリ作成

$ mkdir demo_slds_heroku
$ cd demo_slds_heroku


初期設定

$ npm init


npm initで入力する内容

name:
version:
description:
entry point: (index.js) [server.js]
test command:
git repository:
keywords:
author:
license: (ISC)


package.jsonの内容

{
  "name": "demo_slds_heroku",
  "version": "0.0.0",
  "description": "demo_slds_heroku",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
Step 2: Install node dependencies - Express
$ npm install express --save
Step 3: Create public/index.html
$ mkdir public
$ touch public/index.html

index.htmlの内容

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Playground</title>
  </head>
  <body>
    Kaixo!
  </body>
</html>
Step 4: Create server.js
$ touch server.js


server.jsの内容

var express = require('express');
var app = express();
var port = process.env.PORT || 8080;

// Serve static files
app.use(express.static(__dirname + '/public'));

// Serve your app
console.log('Served: http://localhost:' + port);
app.listen(port);


localhostの起動

$ node server.js

f:id:tyoshikawa1106:20181027181632p:plain


ここでGoogleマップを埋め込んでみます。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Playground</title>
  </head>
  <body>
    <div>
      <iframe src="略" width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
    </div>
  </body>
</html>


この時点ではiframeの幅や高さが固定のためブラウザの幅小さくなると表示されない領域が発生することを確認できます。
f:id:tyoshikawa1106:20181027181918p:plain

f:id:tyoshikawa1106:20181027181931p:plain:w250


続いて最初に記載したリンク先の手順どおりにcssを適用させます。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Playground</title>
    <style>
      .google_map{
        position:relative;
        width:100%;
        height:0;
        padding-top:75%;
      }
      .google_map iframe{
        position:absolute;
        top:0;
        left:0;
        width:100%;
        height:100%;
      }
    </style>
  </head>
  <body>
    <div class="google_map">
      <iframe src="略" width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
    </div>
  </body>
</html>


無事にiframeの内容がページ幅に合わせて動的に切り替わることを確認できました。
f:id:tyoshikawa1106:20181027182404p:plain

f:id:tyoshikawa1106:20181027182418p:plain:w250


目的の動作検証を行うことができましたが、Lightning Design Systemを適用してHerokuへデプロイまでやっておきます。

Step 5: Download the Salesforce Lightning Design System

f:id:tyoshikawa1106:20181027182705p:plain

Step 6: Add components

styleタグの中身を別のcssファイルに移動したり、ヘッダーをつけてこんな感じ。
f:id:tyoshikawa1106:20181027183934p:plain

index.htmlの中身

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" type="text/css" href="/assets/styles/salesforce-lightning-design-system.css" />
    <link rel="stylesheet" type="text/css" href="/css/style.css" />
    <title>Playground</title>
  </head>
  <body>
    <div class="slds-grid slds-wrap">
      <!-- Header -->
      <nav class="slds-col slds-size_1-of-1">
        <div class="slds-page-header">
          <div class="slds-page-header__row">
            <div class="slds-page-header__col-title">
              <div class="slds-media">
                <div class="slds-media__figure">
                  <span class="slds-icon_container slds-icon-standard-opportunity" title="opportunity">
                    <svg class="slds-icon slds-page-header__icon" aria-hidden="true">
                      <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/assets/icons/standard-sprite/svg/symbols.svg#opportunity" />
                    </svg>
                    <span class="slds-assistive-text">Heroku Demo</span>
                  </span>
                </div>
                <div class="slds-media__body">
                  <div class="slds-page-header__name">
                    <div class="slds-page-header__name-title">
                      <h1>
                        <span class="slds-page-header__title slds-truncate" title="Rohde Corp - 80,000 Widgets">Heroku Demo</span>
                      </h1>
                    </div>
                  </div>
                  <p class="slds-page-header__name-meta">T.Yoshikawa Labs</p>
                </div>
              </div>
            </div>
          </div>
        </div>
      </nav>
      <!-- Main -->
      <main class="slds-col slds-size_1-of-1 slds-p-around_small">
        <div class="slds-section">
          <h3 class="slds-section__title slds-theme_shade slds-m-bottom_small">
            <span class="slds-truncate slds-p-horizontal_small" title="Section Title">Google Map</span>
          </h3>
          <!-- Google Map -->
          <div class="google_map">
            <iframe src="略" width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
          </div>
        </div>
      </main>
    </div>
  </body>
</html>


こうなります。
f:id:tyoshikawa1106:20181027183907p:plain

Step 7: Deploy to Heroku
$ touch Procfile

Procfileの内容

web: node server.js


Herokuにログイン

$ heroku login
Email: [your@email.com]
Password: [typing will be hidden]

$ git init
$ heroku create [name-of-your-project]

$ git add .
$ git commit -m "Initial commit"
$ git push heroku master

$ heroku open


こんな感じでHerokuにデプロイしてページを表示できるようにしました。
f:id:tyoshikawa1106:20181027185708p:plain

WebサイトへのSalesforceサイトの組み込み

それではSalesforceサイトの組み込みを試してみます。はじめに外部に公開するためサイト設定でドメインを指定します。
f:id:tyoshikawa1106:20181027190026p:plain


埋め込むためのVisualforceページを用意します。
f:id:tyoshikawa1106:20181027190446p:plain


サイト設定でVisualforceページを表示できるように設定します。これでSalesforceにログインしなくてもアクセスできるVisualforceページを用意できました。
f:id:tyoshikawa1106:20181027190658p:plain


※iframeに別ドメインのサイトを埋め込むことになるのでクリックジャック保護レベルの設定で許可が必要になると思います。
f:id:tyoshikawa1106:20181027203559p:plain


あとは動作確認できるように入力フォームを実装します。
f:id:tyoshikawa1106:20181027191833p:plain


簡易的につくっていますがコードはこんな感じ。

<apex:page showHeader="false" sidebar="false">
    <head>
        <apex:slds />
    </head>
    <body>
        <div xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="vf-page">
            <div class="slds-p-around_small">
                <!-- Field 01 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-01">Form Label 01</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-01" class="slds-input" />
                    </div>
                </div>
                <!-- Field 02 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-02">Form Label 02</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-02" class="slds-input" />
                    </div>
                </div>
                <!-- Field 03 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-03">Form Label 03</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-03" class="slds-input" />
                    </div>
                </div>
                <!-- Field 04 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-04">Form Label 04</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-04" class="slds-input" />
                    </div>
                </div>
                <!-- Field 05 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-05">Form Label 05</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-05" class="slds-input" />
                    </div>
                </div>
                <!-- Field 06 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-06">Form Label 06</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-06" class="slds-input" />
                    </div>
                </div>
                <!-- Field 07 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-07">Form Label 07</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-07" class="slds-input" />
                    </div>
                </div>
                <!-- Field 08 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-08">Form Label 08</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-08" class="slds-input" />
                    </div>
                </div>
                <!-- Field 09 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-09">Form Label 09</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-09" class="slds-input" />
                    </div>
                </div>
                <!-- Field 10 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-10">Form Label 10</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-10" class="slds-input" />
                    </div>
                </div>
                <!-- button -->
                <div class="slds-m-top_small">
                    <button class="slds-button slds-button_brand">問い合わせ</button>
                </div>
            </div>
        </div>
    </body>
</apex:page>


Salesforceサイト側のページが用意できたのでHerokuで用意したWebサイトへiframeで組み込んでみます。まずはレスポンシブ対応無しバージョン。画面サイズに関わらず幅や高さが固定されてしまい正しく表示されません。
f:id:tyoshikawa1106:20181027192757p:plain


続いてレスポンシブ対応ありバージョンです。画面の幅に合わせてフォームが自然に表示されました。
f:id:tyoshikawa1106:20181027194442p:plain


幅を小さくしたときはこのように表示されます。
f:id:tyoshikawa1106:20181027194518p:plain:w200


これでSalesforceサイトのページをWebサイトに埋め込むことができました。iframeによる表示となりますが、Salesforceでつくった入力フォームを自然な見た目で表示することができます。


実際のモバイル端末でアクセスして確認してみました。※iPhone
f:id:tyoshikawa1106:20181027195001p:plain:w200

f:id:tyoshikawa1106:20181027195023p:plain:w200


問題なさそうです。実際のプロジェクトではAndroid端末やIEなどのブラウザで問題ないかも確認してみ他方が良いと思います。(大丈夫だと思いますが)

iframeの高さ指定

サンプルでは%になっていますが、入力フォームなど横幅は変わっても高さを変えたくない場合は、px指定にすることで対応できます。

f:id:tyoshikawa1106:20181027195223p:plain

iframeとページ遷移

当然ですがiframe内でページ遷移するとiframeの中だけでページ遷移が行われます。
f:id:tyoshikawa1106:20181027200908p:plain


JS処理でのページ遷移の場合は下記のような感じにすると親フレームでページ遷移できるので忘れないようにします。

parent.location.href=<url>;


WebサイトへのForce.comサイトページの埋め込みはこんな感じで実現できました。

サンプルコード

最後に今回検証したときのサンプルコードです。

index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" type="text/css" href="/assets/styles/salesforce-lightning-design-system.css" />
    <link rel="stylesheet" type="text/css" href="/css/style.css" />
    <title>Playground</title>
  </head>
  <body>
    <div class="slds-grid slds-wrap">
      <!-- Header -->
      <nav class="slds-col slds-size_1-of-1">
        <div class="slds-page-header">
          <div class="slds-page-header__row">
            <div class="slds-page-header__col-title">
              <div class="slds-media">
                <div class="slds-media__figure">
                  <span class="slds-icon_container slds-icon-standard-opportunity" title="opportunity">
                    <svg class="slds-icon slds-page-header__icon" aria-hidden="true">
                      <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/assets/icons/standard-sprite/svg/symbols.svg#opportunity" />
                    </svg>
                    <span class="slds-assistive-text">Heroku Demo</span>
                  </span>
                </div>
                <div class="slds-media__body">
                  <div class="slds-page-header__name">
                    <div class="slds-page-header__name-title">
                      <h1>
                        <span class="slds-page-header__title slds-truncate" title="T.Yoshikawa Labs">Heroku Demo</span>
                      </h1>
                    </div>
                  </div>
                  <p class="slds-page-header__name-meta">T.Yoshikawa Labs</p>
                </div>
              </div>
            </div>
          </div>
        </div>
      </nav>
      <!-- Main -->
      <main class="slds-col slds-size_1-of-1 slds-p-around_small">
        <!-- Salesforce Form -->
        <div class="slds-section">
          <!-- Salesforce Form Header -->
          <h3 class="slds-section__title slds-theme_shade slds-m-bottom_small">
            <span class="slds-truncate slds-p-horizontal_small" title="Section Title">Salesforce Form</span>
          </h3>
          <!-- Salesforce Form Main -->
          <div class="iframe-section">
            <iframe src="<your salesforce page url>" width="600" height="600" frameborder="0" style="border:0" allowfullscreen></iframe>
          </div>
        </div>
        <!-- Google Map -->
        <div class="slds-section">
          <!-- Google Map Header -->
          <h3 class="slds-section__title slds-theme_shade slds-m-bottom_small">
            <span class="slds-truncate slds-p-horizontal_small" title="Section Title">Google Map</span>
          </h3>
          <!-- Google Map Main -->
          <div class="iframe-section">
            <iframe src="<your google map url>" width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
          </div>
        </div>
      </main>
    </div>
  </body>
</html>
style.css
.iframe-section {
  position:relative;
  width:100%;
  height:0;
  padding-top:650px;
}
.iframe-section iframe {
  position:absolute;
  top:0;
  left:0;
  width:100%;
  height:100%;
  min-height: 600px;
}
Salesforce Form Page
<apex:page showHeader="false" sidebar="false">
    <head>
        <apex:slds />
        <script type="text/javascript">
          function move() {
                parent.location.href="<your salesforce thanks page url>";
            }
        </script>
    </head>
    <body>
        <div xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="vf-page">
            <div class="slds-p-around_small">
                <!-- Field 01 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-01">Form Label 01</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-01" class="slds-input" />
                    </div>
                </div>
                <!-- Field 02 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-02">Form Label 02</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-02" class="slds-input" />
                    </div>
                </div>
                <!-- Field 03 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-03">Form Label 03</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-03" class="slds-input" />
                    </div>
                </div>
                <!-- Field 04 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-04">Form Label 04</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-04" class="slds-input" />
                    </div>
                </div>
                <!-- Field 05 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-05">Form Label 05</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-05" class="slds-input" />
                    </div>
                </div>
                <!-- Field 06 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-06">Form Label 06</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-06" class="slds-input" />
                    </div>
                </div>
                <!-- Field 07 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-07">Form Label 07</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-07" class="slds-input" />
                    </div>
                </div>
                <!-- Field 08 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-08">Form Label 08</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-08" class="slds-input" />
                    </div>
                </div>
                <!-- Field 09 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-09">Form Label 09</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-09" class="slds-input" />
                    </div>
                </div>
                <!-- Field 10 -->
                <div class="slds-form-element">
                    <label class="slds-form-element__label" for="form-element-10">Form Label 10</label>
                    <div class="slds-form-element__control">
                        <input type="text" id="form-element-10" class="slds-input" />
                    </div>
                </div>
                <!-- button -->
                <div class="slds-m-top_small">
                    <button class="slds-button slds-button_brand" onclick="move()">問い合わせ</button>
                </div>
            </div>
        </div>
    </body>
</apex:page>
Salesforce Form Thanks Page
<apex:page showHeader="false" sidebar="false">
    <head>
        <apex:slds />
        <style>
        	* {
            	background-color: #255E9E;
                font-size: 20px;
                color: #fff;
            }
        </style>
    </head>
    <body>
        <div xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="vf-page">
            <div class="slds-p-around_small">
                Thanks!
            </div>
        </div>
    </body>
</apex:page>