57319


## 現状

キャンバスに任意の画像をアップロードし、キャンバスに描画する機能を実装しています。  
下記リンク先で動作をご確認いただけます。

[demo](https://jsbin.com/wacacixobo/1/edit?output)

キャンバスに画像を読み込むと、キャンバスとフッターがフェードインします。  
フッターはスクロールに追尾します。

## 使用しているライブラリ

・jQuery  
・Fabric.js

## 問題点

一番下までスクロールしても、フッターがキャンバスに被ってしまいます。  
縦長の画像を読み込んでいただくと、問題となっている状態が分かりやすいです。

縦長の画像を用意したので、よろしければご使用ください。  
[画像出典：pixabay](https://pixabay.com/ja/vectors/%E3%82%AD%E3%83%AA%E3%83%B3-%E5%93%BA%E4%B9%B3%E5%8B%95%E7%89%A9-%E5%8B%95%E7%89%A9-40035/)

[![サンプル画像](https://i.stack.imgur.com/hOgs2.png)](https://i.stack.imgur.com/hOgs2.png)

## 解決したいこと、ご助力いただきたいこと

一番下までスクロールした際、フッターがキャンバスに被らないようにしたいです。  
また、デバイスやディスプレイサイズを問わない方法で解決したいです。

## 試したこと

CSSで`#cnvArea`に`padding-bottom`を設定すると、一番下までスクロールした際の、フッターとキャンバスの被りを回避できました。

しかし`padding-bottom`で設定した値は、ディスプレイのサイズによって必要な値が異なります。  
例えば上記のdemoで言うと、Outputタブのみを表示した場合の大きいウインドウサイズでは被りを回避できましたが、HTML、CSS、JavaScriptタブを表示した場合の小さいウインドウサイズでは、被りを回避できませんでした。

## ソースコード

[code]

    $('#file').on('change', function () {
        $('#view').fadeIn();
        var fr = new FileReader();
        fr.onload = function (e) {
            input(e.target.result);
        };
        fr.readAsDataURL(this.files[0]);
    });
    
    var canvas = new fabric.Canvas('c');
    
    var input = function (url) {
        fabric.Image.fromURL(url, function (img){
          var wS = canvas.width / img.width;
          img.scale(wS);
          canvas.setHeight(img.height * wS);
          canvas.clear();
          canvas.add(img).renderAll();
          img.selectable = false;
        });
    };
[/code]

[code]

    html{
      text-align: center;
    }
    
    #view{
      display: none;
    }
    
    .canvas-container{
     margin: auto
    }
    
    /* #cnvArea{
      padding-bottom: 25%;
    } */
    
    canvas{
      border: 2px solid black;
    }
    
    #optArea{
      min-height: 40%;
      position: fixed;
      width: 100vw;
      left: 0;
      bottom: 0;
      background-color: black;
    }
[/code]

[code]

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width">
        <title>test</title>
      </head>
      <body>
        <input id="file" type="file" accept="image/*">
        <div id="view">
          <div id="cnvArea">
            <canvas id="c" width="700"></canvas>
          </div>
          <div id="optArea">
            <input type="range" id="value" value="0.5" min="0" max="1" step="0.01">
            <br>
            <button>a</button>
            <button>b</button>
            <button>c</button>
            <button>d</button>
          </div>
        </div>
        <script src="https://code.jquery.com/jquery-3.1.0.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.3.2/fabric.min.js"></script>
        </body>
    </html>
[/code]


CC BY-SA 4.0
2019-08-12T03:01:48.807
57311
2019-08-12T13:44:11.310
2019-08-12T03:07:03.073
35433
35433
question
javascript html css
追従するフッターをcanvas領域の下まで下げたい。


`position` プロパティに fixed
を指定した場合、そのボックスはビューポートに対して固定されます[[1]](https://www.w3.org/TR/CSS22/visuren.html#choose-
position)。

> ### 9.3.1 Choosing a positioning scheme: 'position'
> property[[1]](https://www.w3.org/TR/CSS22/visuren.html#choose-position)
>
> The box's position is calculated according to the 'absolute' model, but in
> addition, the box is fixed with respect to some reference. As with the
> 'absolute' model, the box's margins do not collapse with any other margins.
> In the case of handheld, projection, screen, tty, and tv media types, the
> box is fixed with respect to the viewport and does not move when scrolled.

よって、フッターへ対して設定している `min-height` プロパティの値は、 **ビューポートを基準とした相対的な高さを取る**
ことになります。また、 CSS Values and Units Module Level 3 にて追加された `vh` という単位は、
**初期包含ブロックの高さの割合を取ります**[[2]](https://drafts.csswg.org/css-values-3/#viewport-
relative-lengths)。これらより、当該 `min-height` プロパティの単位はパーセントから `vh`
へ置き換えることが出来ることがわかります。

> ### § 5.1.2. Viewport-percentage Lengths: the vw, vh, vmin, vmax
> units[[2]](https://drafts.csswg.org/css-values-3/#viewport-relative-lengths)
>
> `vh unit`  
>  Equal to 1% of the height of the initial containing block.

このようにすることで、 `padding-bottom`
プロパティを用いてフッターと同じ高さの余白を作ることが出来るようになり、ページ最下部にてフッターとキャンバスが重なる問題を解決することが出来ます。

[code]

    body {
      padding-bottom: 40vh;  /* 追加 */
    }
    
    #optArea {
      min-height: 40vh;  /* 変更 */
      position: fixed;
      width: 100vw;
      left: 0;
      bottom: 0;
      background-color: black;
    }
    
[/code]

[code]

    $('#file').on('change', function() {
      $('#view').fadeIn();
      var fr = new FileReader();
      fr.onload = function(e) {
        input(e.target.result);
      };
      fr.readAsDataURL(this.files[0]);
    });
    
    var canvas = new fabric.Canvas('c');
    
    var input = function(url) {
      fabric.Image.fromURL(url, function(img) {
        var wS = canvas.width / img.width;
        img.scale(wS);
        canvas.setHeight(img.height * wS);
        canvas.clear();
        canvas.add(img).renderAll();
        img.selectable = false;
      });
    };
[/code]

[code]

    html {
      text-align: center;
    }
    
    body {
      padding-bottom: 40vh;  /* 追加 */
    }
    
    #view {
      display: none;
    }
    
    .canvas-container {
      margin: auto
    }
    
    canvas {
      border: 2px solid black;
    }
    
    #optArea {
      min-height: 40vh;  /* 変更 */
      position: fixed;
      width: 100vw;
      left: 0;
      bottom: 0;
      background-color: black;
    }
[/code]

[code]

    <!DOCTYPE html>
    <html>
    
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>test</title>
    </head>
    
    <body>
      <input id="file" type="file" accept="image/*">
      <div id="view">
        <div id="cnvArea">
          <canvas id="c" width="700"></canvas>
        </div>
        <div id="optArea">
          <input type="range" id="value" value="0.5" min="0" max="1" step="0.01">
          <br>
          <button>a</button>
          <button>b</button>
          <button>c</button>
          <button>d</button>
        </div>
      </div>
      <script src="https://code.jquery.com/jquery-3.1.0.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.3.2/fabric.min.js"></script>
    </body>
    
    </html>
[/code]

* * *

今回の場合は当てはまりませんが、もし高さがビューポートによらない場合、 CSS だけで解決をすることが難しいため、 JavaScript
により動的にフッターの高さを取得し、それを余白の高さとして適用する方法が簡単です。

[code]

    $(window).on("resize", function() {
      var optAreaHeight = $("#optArea").outerHeight();
      $("#view").css("padding-bottom", optAreaHeight);
    });
    
[/code]

[code]

    $('#file').on('change', function() {
      $('#view').fadeIn();
      var fr = new FileReader();
      fr.onload = function(e) {
        input(e.target.result);
      };
      fr.readAsDataURL(this.files[0]);
    });
    
    $(window).on("resize", function() { // 追加
      var optAreaHeight = $("#optArea").outerHeight();
      $("#view").css("padding-bottom", optAreaHeight);
    });
    
    var canvas = new fabric.Canvas('c');
    
    var input = function(url) {
      fabric.Image.fromURL(url, function(img) {
        var wS = canvas.width / img.width;
        img.scale(wS);
        canvas.setHeight(img.height * wS);
        canvas.clear();
        canvas.add(img).renderAll();
        img.selectable = false;
      });
    };
[/code]

[code]

    html {
      text-align: center;
    }
    
    #view {
      display: none;
    }
    
    .canvas-container {
      margin: auto
    }
    
    canvas {
      border: 2px solid black;
    }
    
    #optArea {
      min-height: 40%;
      position: fixed;
      width: 100vw;
      left: 0;
      bottom: 0;
      background-color: black;
    }
[/code]

[code]

    <!DOCTYPE html>
    <html>
    
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>test</title>
    </head>
    
    <body>
      <input id="file" type="file" accept="image/*">
      <div id="view">
        <div id="cnvArea">
          <canvas id="c" width="700"></canvas>
        </div>
        <div id="optArea">
          <input type="range" id="value" value="0.5" min="0" max="1" step="0.01">
          <br>
          <button>a</button>
          <button>b</button>
          <button>c</button>
          <button>d</button>
        </div>
      </div>
      <script src="https://code.jquery.com/jquery-3.1.0.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.3.2/fabric.min.js"></script>
    </body>
    
    </html>
[/code]


CC BY-SA 4.0
2019-08-12T13:44:11.310
57319
2019-08-12T13:44:11.310
32986
57311
answer